diff --git a/.github/ISSUE_TEMPLATE/get-help.md b/.github/ISSUE_TEMPLATE/get-help.md index b1e29541..7426ade0 100644 --- a/.github/ISSUE_TEMPLATE/get-help.md +++ b/.github/ISSUE_TEMPLATE/get-help.md @@ -24,7 +24,7 @@ If IW4x is crashing, include the minidump file and the crash address in text for Describe any steps you've already taken to try to get past this issue. Have you found a workaround? **What version of IW4x are you using?** -`iw4x.exe -version` will show you the version. Please make sure you are up to date with the latest master branch. +`iw4x.exe -version` will show you the version. Please make sure you are up to date with the latest build from the master branch. **Anything else we should know?** Add any other context about the problem here. diff --git a/.gitmodules b/.gitmodules index 1f577bd3..336e750f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,10 +2,6 @@ path = deps/zlib url = https://github.com/madler/zlib.git branch = develop -[submodule "deps/json11"] - path = deps/json11 - url = https://github.com/dropbox/json11.git - branch = master [submodule "deps/libtommath"] path = deps/libtommath url = https://github.com/libtom/libtommath.git @@ -35,3 +31,6 @@ [submodule "deps/GSL"] path = deps/GSL url = https://github.com/microsoft/GSL.git +[submodule "deps/nlohmannjson"] + path = deps/nlohmannjson + url = https://github.com/nlohmann/json.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 424f3859..46f0f381 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,37 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.7.5] - 2022-09-03 + +### Added + +- Add `bg_rocketJumpScale` Dvar (#413) +- Add `CastFloat` GSC function (#414) +- Add `Strtol` GSC function (#414) +- Add `bg_lean` Dvar (#421 +- Add voice chat (#425) +- Add `vote` & `callvote` client commands (#447) +- Add `kill` client command (#451) +- Add `voteKick`, `voteTempBan`, `voteTypeMap`, `voteMap` and `voteGame` UI script tokens (#456) +- Add `Int64IsInt`, `Int64ToInt` and `Int64OP` GSC functions (#419) + +### Changed + +- Steam status is no longer set to busy (#417) +- `HttpGet`& `HttpCancel` are disabled for security reasons (#449) +- 'g_allowVote' is a replicated Dvar (#457) + +### Fixed + +- Fixed `startSingleplayer` command (#404) +- General stability update + +### Known issues + +- HTTPS is not supported for fast downloads at the moment. +- Sound issue fix is experimental as the bug is not fully understood. +- `reloadmenus` command does not free resources used by custom menus. + ## [0.7.4] - 2022-07-28 ### Added @@ -187,7 +218,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. - Fixed slow motion during final killcams (#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 (#144) +- Fixed issue with servers displaying an invalid player count (#113) ### Known issues diff --git a/README.md b/README.md index aca253ca..487f7a02 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ # IW4x: Client -## How to compile +## Compile from source -- Run `premake5 vs2022` or use the delivered `generate.bat`. +- Clone the Git repo. Do NOT download it as ZIP, that won't work. +- Update the submodules and run `premake5 vs2022` or simply use the delivered `generate.bat`. - Build via solution file in `build\iw4x.sln`. ## Premake arguments @@ -22,7 +23,6 @@ | `--force-unit-tests` | Always compile unit tests. | | `--force-exception-handler` | Install custom unhandled exception handler even for Debug builds. | | `--disable-binary-check` | Do not perform integrity checks on the exe. | -| `--iw4x-zones` | Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches. | ## Command line arguments diff --git a/deps/GSL b/deps/GSL index 330583f4..10df83d2 160000 --- a/deps/GSL +++ b/deps/GSL @@ -1 +1 @@ -Subproject commit 330583f47800c60cf001239550d291d16274756a +Subproject commit 10df83d292bf5bbdc487e57dc8c2dc8c7a01f4d1 diff --git a/deps/json11 b/deps/json11 deleted file mode 160000 index 2df9473f..00000000 --- a/deps/json11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2df9473fb3605980db55ecddf34392a2e832ad35 diff --git a/deps/libtomcrypt b/deps/libtomcrypt index 8fd5dad9..ddfe2e8a 160000 --- a/deps/libtomcrypt +++ b/deps/libtomcrypt @@ -1 +1 @@ -Subproject commit 8fd5dad96b56beb53b5cf199cb63fb76dfba32bb +Subproject commit ddfe2e8aa7c4239463a8a1d26724aef123333549 diff --git a/deps/nlohmannjson b/deps/nlohmannjson new file mode 160000 index 00000000..307c053b --- /dev/null +++ b/deps/nlohmannjson @@ -0,0 +1 @@ +Subproject commit 307c053b9b250abc6e6d478a4336fd98592ae173 diff --git a/deps/premake/json11.lua b/deps/premake/json11.lua deleted file mode 100644 index 60ea05d7..00000000 --- a/deps/premake/json11.lua +++ /dev/null @@ -1,33 +0,0 @@ -json11 = { - source = path.join(dependencies.basePath, "json11"), -} - -function json11.import() - links {"json11"} - - json11.includes() -end - -function json11.includes() - includedirs {json11.source} -end - -function json11.project() - project "json11" - language "C++" - cppdialect "C++11" - - files - { - path.join(json11.source, "*.cpp"), - path.join(json11.source, "*.hpp"), - } - - warnings "Off" - - defines {"_LIB"} - removedefines {"_USRDLL", "_DLL"} - kind "StaticLib" -end - -table.insert(dependencies, json11) diff --git a/deps/premake/nlohmannjson.lua b/deps/premake/nlohmannjson.lua new file mode 100644 index 00000000..8cdf6217 --- /dev/null +++ b/deps/premake/nlohmannjson.lua @@ -0,0 +1,18 @@ +nlohmannjson = { + source = path.join(dependencies.basePath, "nlohmannjson"), +} + +function nlohmannjson.import() + nlohmannjson.includes() +end + +function nlohmannjson.includes() + includedirs { + path.join(nlohmannjson.source, "single_include/nlohmann") + } +end + +function nlohmannjson.project() +end + +table.insert(dependencies, nlohmannjson) diff --git a/deps/protobuf b/deps/protobuf index fb6f8da0..50bdb174 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit fb6f8da08b60b6beb5bb360d79dd3feda0147da7 +Subproject commit 50bdb17409d4133d51ab6cfa095700f4c816576e diff --git a/deps/zlib b/deps/zlib index 2333419c..5752b171 160000 --- a/deps/zlib +++ b/deps/zlib @@ -1 +1 @@ -Subproject commit 2333419cd76cb9ae5f15c9b240b16a2052b27691 +Subproject commit 5752b171fd4cc96b8d1f9526ec1940199c6e9740 diff --git a/premake5.lua b/premake5.lua index 5ca05e35..3f36f4bd 100644 --- a/premake5.lua +++ b/premake5.lua @@ -86,11 +86,6 @@ newoption { description = "Do not perform integrity checks on the exe." } -newoption { - trigger = "iw4x-zones", - description = "Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches." -} - newaction { trigger = "version", description = "Returns the version string for the current commit of the source code.", @@ -268,9 +263,6 @@ workspace "iw4x" if _OPTIONS["disable-binary-check"] then defines {"DISABLE_BINARY_CHECK"} end - if _OPTIONS["iw4x-zones"] then - defines {"GENERATE_IW4X_SPECIFIC_ZONES"} - end -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index c1163385..014a0782 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -112,6 +112,8 @@ namespace Components Loader::Register(new Ceg()); Loader::Register(new UserInfo()); Loader::Register(new Events()); + Loader::Register(new Voice()); + Loader::Register(new Vote()); Loader::Register(new GSC()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 67bcc26f..71e3b530 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -143,5 +143,7 @@ namespace Components #include "Modules/Ceg.hpp" #include "Modules/UserInfo.hpp" #include "Modules/Events.hpp" +#include "Modules/Voice.hpp" +#include "Modules/Vote.hpp" #include "Modules/GSC/GSC.hpp" diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index 04079444..d450d50b 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -601,7 +601,7 @@ namespace Components } } - json11::Json vertexData = json11::Json::object + nlohmann::json vertexData = json11::Json::object { { "name", vertexdecl->name }, { "streamCount", vertexdecl->streamCount }, @@ -651,7 +651,7 @@ namespace Components literalConsts.push_back(curArg->u.literalConst[3]); } - json11::Json argData = json11::Json::object + nlohmann::json argData = json11::Json::object { { "type", curArg->type }, { "value", literalConsts }, @@ -660,7 +660,7 @@ namespace Components } else if (curArg->type == 3 || curArg->type == 5) { - json11::Json argData = json11::Json::object + nlohmann::json argData = json11::Json::object { { "type", curArg->type }, { "firstRow", curArg->u.codeConst.firstRow }, @@ -671,7 +671,7 @@ namespace Components } else { - json11::Json argData = json11::Json::object + nlohmann::json argData = json11::Json::object { { "type", curArg->type }, { "value", static_cast(curArg->u.codeSampler) }, @@ -680,7 +680,7 @@ namespace Components } } - json11::Json passData = json11::Json::object + nlohmann::json passData = json11::Json::object { { "perObjArgCount", curPass->perObjArgCount }, { "perPrimArgCount", curPass->perPrimArgCount }, @@ -693,7 +693,7 @@ namespace Components passDataArray.push_back(passData); } - json11::Json techData = json11::Json::object + nlohmann::json techData = json11::Json::object { { "name", curTech->name }, { "index", technique }, @@ -708,7 +708,7 @@ namespace Components fwrite(&stringData[0], stringData.size(), 1, fp); fclose(fp); - json11::Json techsetTechnique = json11::Json::object + nlohmann::json techsetTechnique = json11::Json::object { { "name", curTech->name }, { "index", technique }, @@ -721,7 +721,7 @@ namespace Components } } - json11::Json techsetData = json11::Json::object + nlohmann::json techsetData = json11::Json::object { { "name", techset->name }, { "techniques", techniques }, diff --git a/src/Components/Modules/AssetInterfaces/IFont_s.cpp b/src/Components/Modules/AssetInterfaces/IFont_s.cpp index 22a57d50..52093f54 100644 --- a/src/Components/Modules/AssetInterfaces/IFont_s.cpp +++ b/src/Components/Modules/AssetInterfaces/IFont_s.cpp @@ -100,26 +100,19 @@ namespace Assets if (fontDefFile.exists() && fontFile.exists()) { - std::string errors; - auto fontDef = json11::Json::parse(fontDefFile.getBuffer(), errors); - - if (!errors.empty()) - { - Components::Logger::Error(Game::ERR_FATAL, "Font define {} is broken: {}", name, errors); - return; - } + auto fontDef = nlohmann::json::parse(fontDefFile.getBuffer()); if (!fontDef.is_object()) { - Components::Logger::Error(Game::ERR_FATAL, "Font define {} is invalid {}", name, errors); + Components::Logger::Error(Game::ERR_FATAL, "Font define {} is invalid", name); return; } - int w = fontDef["textureWidth"].int_value(); - int h = fontDef["textureHeight"].int_value(); + int w = fontDef["textureWidth"].get(); + int h = fontDef["textureHeight"].get(); - int size = fontDef["size"].int_value(); - int yOffset = fontDef["yOffset"].int_value(); + int size = fontDef["size"].get(); + int yOffset = fontDef["yOffset"].get(); auto* pixels = builder->getAllocator()->allocateArray(w * h); @@ -153,8 +146,9 @@ namespace Assets if (fontDef["charset"].is_array()) { - for (auto& ch : fontDef["charset"].array_items()) - charset.push_back(static_cast(ch.int_value())); + nlohmann::json::array_t charsetArray = fontDef["charset"]; + for (auto& ch : charsetArray) + charset.push_back(static_cast(ch.get())); // order matters std::sort(charset.begin(), charset.end()); diff --git a/src/Components/Modules/AssetInterfaces/IMaterial.cpp b/src/Components/Modules/AssetInterfaces/IMaterial.cpp index c594f970..d1df2bbd 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterial.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterial.cpp @@ -332,165 +332,13 @@ namespace Assets header->material = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).material; } - void IMaterial::loadJson(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) + void IMaterial::loadJson(Game::XAssetHeader* header, const std::string& name, [[maybe_unused]] Components::ZoneBuilder::Zone* builder) { Components::FileSystem::File materialInfo(Utils::String::VA("materials/%s.json", name.data())); if (!materialInfo.exists()) return; - std::string errors; - json11::Json infoData = json11::Json::parse(materialInfo.getBuffer(), errors); - - if (!infoData.is_object()) - { - Components::Logger::Error(Game::ERR_FATAL, "Failed to load material information for {}!", name); - return; - } - - auto base = infoData["base"]; - - if (!base.is_string()) - { - Components::Logger::Error(Game::ERR_FATAL, "No valid material base provided for {}!", name); - return; - } - - Game::Material* baseMaterial = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, base.string_value().data()).material; - - if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!? - { - Components::Logger::Error(Game::ERR_FATAL, "Basematerial '{}' not found for {}!", base.string_value(), name); - return; - } - - Game::Material* material = builder->getAllocator()->allocate(); - - if (!material) - { - Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate material structure!"); - return; - } - - // Copy base material to our structure - std::memcpy(material, baseMaterial, sizeof(Game::Material)); - material->info.name = builder->getAllocator()->duplicateString(name); - - material->info.textureAtlasRowCount = 1; - material->info.textureAtlasColumnCount = 1; - - // Load animation frames - auto anims = infoData["anims"]; - if (anims.is_array()) - { - auto animCoords = anims.array_items(); - - if (animCoords.size() >= 2) - { - auto animCoordX = animCoords[0]; - auto animCoordY = animCoords[1]; - - if (animCoordX.is_number()) - { - material->info.textureAtlasColumnCount = static_cast(animCoordX.number_value()) & 0xFF; - } - - if (animCoordY.is_number()) - { - material->info.textureAtlasRowCount = static_cast(animCoordY.number_value()) & 0xFF; - } - } - } - - // Model surface textures are special, they need a special order and whatnot - bool replaceTexture = Utils::String::StartsWith(name, "mc/"); - if (replaceTexture) - { - Game::MaterialTextureDef* textureTable = builder->getAllocator()->allocateArray(baseMaterial->textureCount); - std::memcpy(textureTable, baseMaterial->textureTable, sizeof(Game::MaterialTextureDef) * baseMaterial->textureCount); - material->textureTable = textureTable; - material->textureCount = baseMaterial->textureCount; - } - - // Load referenced textures - auto textures = infoData["textures"]; - if (textures.is_array()) - { - std::vector textureList; - - for (auto& texture : textures.array_items()) - { - if (!texture.is_array()) continue; - if (textureList.size() >= 0xFF) break; - - auto textureInfo = texture.array_items(); - if (textureInfo.size() < 2) continue; - - auto map = textureInfo[0]; - auto image = textureInfo[1]; - if (!map.is_string() || !image.is_string()) continue; - - Game::MaterialTextureDef textureDef; - - textureDef.semantic = 0; // No water image - textureDef.samplerState = -30; - textureDef.nameEnd = map.string_value().back(); - textureDef.nameStart = map.string_value().front(); - textureDef.nameHash = Game::R_HashString(map.string_value().data()); - - textureDef.u.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, image.string_value(), builder).image; - - if (replaceTexture) - { - bool applied = false; - - for (char i = 0; i < baseMaterial->textureCount; ++i) - { - if (material->textureTable[i].nameHash == textureDef.nameHash) - { - applied = true; - material->textureTable[i].u.image = textureDef.u.image; - break; - } - } - - if (!applied) - { - Components::Logger::Error(Game::ERR_FATAL, "Unable to find texture for map '{}' in {}!", - map.string_value(), baseMaterial->info.name); - } - } - else - { - textureList.push_back(textureDef); - } - } - - if (!replaceTexture) - { - if (!textureList.empty()) - { - Game::MaterialTextureDef* textureTable = builder->getAllocator()->allocateArray(textureList.size()); - - if (!textureTable) - { - Components::Logger::Error(Game::ERR_FATAL, "Failed to allocate texture table!"); - return; - } - - std::memcpy(textureTable, textureList.data(), sizeof(Game::MaterialTextureDef) * textureList.size()); - - material->textureTable = textureTable; - } - else - { - material->textureTable = nullptr; - } - - material->textureCount = static_cast(textureList.size()) & 0xFF; - } - } - - header->material = material; + header->material = nullptr; } void IMaterial::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) diff --git a/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp b/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp index 86cc1dd7..d70c9aaa 100644 --- a/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp +++ b/src/Components/Modules/AssetInterfaces/Isnd_alias_list_t.cpp @@ -5,10 +5,10 @@ namespace Assets { void Isnd_alias_list_t::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - Components::FileSystem::File aliasFile(Utils::String::VA("sounds/%s", name.c_str())); + Components::FileSystem::File aliasFile(Utils::String::VA("sounds/%s.json", name.data())); if (!aliasFile.exists()) { - header->sound = Components::AssetHandler::FindOriginalAsset(this->getType(), name.c_str()).sound; + header->sound = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).sound; return; } @@ -19,11 +19,10 @@ namespace Assets return; } - std::string errors; - json11::Json infoData = json11::Json::parse(aliasFile.getBuffer(), errors); - json11::Json aliasesContainer = infoData["head"]; + nlohmann::json infoData = nlohmann::json::parse(aliasFile.getBuffer()); + nlohmann::json aliasesContainer = infoData["head"]; - auto aliases = aliasesContainer.array_items(); + nlohmann::json::array_t aliases = aliasesContainer; aliasList->count = aliases.size(); @@ -39,7 +38,7 @@ namespace Assets for (size_t i = 0; i < aliasList->count; i++) { - json11::Json head = aliasesContainer[i]; + nlohmann::json head = aliasesContainer[i]; if (!infoData.is_object()) { @@ -211,37 +210,37 @@ namespace Assets { alias->soundFile->exists = true; - alias->aliasName = builder->getAllocator()->duplicateString(aliasName.string_value().c_str()); + alias->aliasName = builder->getAllocator()->duplicateString(aliasName.get()); if (subtitle.is_string()) { - alias->subtitle = builder->getAllocator()->duplicateString(subtitle.string_value().c_str()); + alias->subtitle = builder->getAllocator()->duplicateString(subtitle.get()); } if (secondaryAliasName.is_string()) { - alias->secondaryAliasName = builder->getAllocator()->duplicateString(secondaryAliasName.string_value().c_str()); + alias->secondaryAliasName = builder->getAllocator()->duplicateString(secondaryAliasName.get()); } if (chainAliasName.is_string()) { - alias->chainAliasName = builder->getAllocator()->duplicateString(chainAliasName.string_value().c_str()); + alias->chainAliasName = builder->getAllocator()->duplicateString(chainAliasName.get()); } - alias->sequence = sequence.int_value(); - alias->volMin = float(volMin.number_value()); - alias->volMax = float(volMax.number_value()); - alias->pitchMin = float(pitchMin.number_value()); - alias->pitchMax = float(pitchMax.number_value()); - alias->distMin = float(distMin.number_value()); - alias->distMax = float(distMax.number_value()); - alias->flags = flags.int_value(); - alias->___u15.slavePercentage = float(slavePercentage.number_value()); - alias->probability = float(probability.number_value()); - alias->lfePercentage = float(lfePercentage.number_value()); - alias->centerPercentage = float(centerPercentage.number_value()); - alias->startDelay = startDelay.int_value(); - alias->envelopMin = float(envelopMin.number_value()); - alias->envelopMax = float(envelopMax.number_value()); - alias->envelopPercentage = float(envelopPercentage.number_value()); + alias->sequence = sequence.get(); + alias->volMin = volMin.get(); + alias->volMax = volMax.get(); + alias->pitchMin = pitchMin.get(); + alias->pitchMax = pitchMax.get(); + alias->distMin = distMin.get(); + alias->distMax = distMax.get(); + alias->flags = flags.get(); + alias->___u15.slavePercentage = slavePercentage.get(); + alias->probability = probability.get(); + alias->lfePercentage = lfePercentage.get(); + alias->centerPercentage = centerPercentage.get(); + alias->startDelay = startDelay.get(); + alias->envelopMin = envelopMin.get(); + alias->envelopMax = envelopMax.get(); + alias->envelopPercentage = envelopPercentage.get(); // Speaker map object if (!speakerMap.is_null()) @@ -253,12 +252,12 @@ namespace Assets return; } - alias->speakerMap->name = builder->getAllocator()->duplicateString(speakerMap["name"].string_value().c_str()); - alias->speakerMap->isDefault = speakerMap["isDefault"].bool_value(); + alias->speakerMap->name = builder->getAllocator()->duplicateString(speakerMap["name"].get()); + alias->speakerMap->isDefault = speakerMap["isDefault"].get(); if (speakerMap["channelMaps"].is_array()) { - json11::Json::array channelMaps = speakerMap["channelMaps"].array_items(); + nlohmann::json::array_t channelMaps = speakerMap["channelMaps"]; assert(channelMaps.size() <= 4); @@ -268,19 +267,19 @@ namespace Assets // subChannelIndex should never exceed 1 for (size_t subChannelIndex = 0; subChannelIndex < 2; subChannelIndex++) { - json11::Json channelMap = channelMaps[channelMapIndex * 2 + subChannelIndex]; // 0-3 + nlohmann::json channelMap = channelMaps[channelMapIndex * 2 + subChannelIndex]; // 0-3 - auto speakers = channelMap["speakers"].array_items(); + nlohmann::json::array_t speakers = channelMap["speakers"]; alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakerCount = speakers.size(); for (size_t speakerIndex = 0; speakerIndex < alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakerCount; speakerIndex++) { auto speaker = speakers[speakerIndex]; - alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].levels[0] = static_cast(speaker["levels0"].number_value()); - alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].levels[1] = static_cast(speaker["levels1"].number_value()); - alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].numLevels = static_cast(speaker["numLevels"].number_value()); - alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].speaker = static_cast(speaker["speaker"].number_value()); + alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].levels[0] = speaker["levels0"].get(); + alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].levels[1] = speaker["levels1"].get(); + alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].numLevels = speaker["numLevels"].get(); + alias->speakerMap->channelMaps[channelMapIndex][subChannelIndex].speakers[speakerIndex].speaker = speaker["speaker"].get(); } } } @@ -289,7 +288,7 @@ namespace Assets if (volumeFalloffCurve.is_string()) { - std::string fallOffCurve = volumeFalloffCurve.string_value(); + std::string fallOffCurve = volumeFalloffCurve.get(); if (fallOffCurve.size() == 0) { @@ -305,16 +304,16 @@ namespace Assets alias->volumeFalloffCurve = curve; } - if (static_cast(type.number_value()) == Game::snd_alias_type_t::SAT_LOADED) // Loaded + if (static_cast(type.get()) == Game::snd_alias_type_t::SAT_LOADED) // Loaded { alias->soundFile->type = Game::SAT_LOADED; - alias->soundFile->u.loadSnd = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, soundFile.string_value().c_str(), builder).loadSnd; + alias->soundFile->u.loadSnd = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, soundFile.get(), builder).loadSnd; } - else if (static_cast(type.number_value()) == Game::snd_alias_type_t::SAT_STREAMED) // Streamed + else if (static_cast(type.get()) == Game::snd_alias_type_t::SAT_STREAMED) // Streamed { alias->soundFile->type = Game::SAT_STREAMED; - std::string streamedFile = soundFile.string_value(); + std::string streamedFile = soundFile.get(); std::string directory = ""s; int split = streamedFile.find_last_of('/'); @@ -329,7 +328,7 @@ namespace Assets } else { - Components::Logger::Error(Game::ERR_FATAL, "Failed to parse sound {}! Invalid sound type {}\n", name, type.string_value()); + Components::Logger::Error(Game::ERR_FATAL, "Failed to parse sound {}! Invalid sound type {}\n", name, type.get()); return; } diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index 01f87c59..8bdc7536 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -130,7 +130,7 @@ namespace Components // Parse proto data Proto::Auth::Connect connectData; - if (msg->cursize <= 12 || !connectData.ParseFromString(std::string(&msg->data[12], msg->cursize - 12))) + if (msg->cursize <= 12 || !connectData.ParseFromString(std::string(reinterpret_cast(&msg->data[12]), msg->cursize - 12))) { Network::Send(address, "error\nInvalid connect packet!"); return; @@ -233,7 +233,7 @@ namespace Components return; } - Logger::Debug("Verified XUID {:#X} ({}) from {}", xuid, userLevel, address.getCString()); + Logger::Debug("Verified XUID {:#X} ({}) from {}", xuid, userLevel, address.getString()); Game::SV_DirectConnect(*address.get()); } #endif @@ -472,7 +472,7 @@ namespace Components }); } - UIScript::Add("security_increase_cancel", [](UIScript::Token) + UIScript::Add("security_increase_cancel", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { Auth::TokenContainer.cancel = true; Logger::Print("Token incrementation process canceled!\n"); diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index 45382bdc..dd7e0bec 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -107,7 +107,7 @@ namespace Components ipEntry.bytes[3] & 0xFF)); } - const json11::Json bans = json11::Json::object + const nlohmann::json bans = nlohmann::json { { "ip", ipVector }, { "id", idVector }, @@ -131,13 +131,7 @@ namespace Components } std::string error; - const auto banData = json11::Json::parse(bans.getBuffer(), error); - - if (!error.empty()) - { - Logger::PrintError(Game::CON_CHANNEL_ERROR, "Failed to parse bans.json: {}\n", error); - return; - } + const auto banData = nlohmann::json::parse(bans.getBuffer()); if (!banData.is_object()) { @@ -150,12 +144,15 @@ namespace Components if (idList.is_array()) { - for (auto &idEntry : idList.array_items()) + nlohmann::json::array_t arr = idList; + + for (auto &idEntry : arr) { if (idEntry.is_string()) { SteamID id; - id.bits = strtoull(idEntry.string_value().data(), nullptr, 16); + auto guid = idEntry.get(); + id.bits = std::strtoull(guid.data(), nullptr, 16); list->idList.push_back(id); } @@ -164,11 +161,13 @@ namespace Components if (ipList.is_array()) { - for (auto &ipEntry : ipList.array_items()) + nlohmann::json::array_t arr = ipList; + + for (auto &ipEntry : arr) { if (ipEntry.is_string()) { - Network::Address addr(ipEntry.string_value()); + Network::Address addr(ipEntry.get()); list->ipList.push_back(addr.getIP()); } @@ -181,7 +180,7 @@ namespace Components SteamID guid; guid.bits = cl->steamID; - InsertBan({guid, cl->netchan.remoteAddress.ip}); + InsertBan({guid, cl->header.netchan.remoteAddress.ip}); Game::SV_DropClient(cl, reason.data(), true); } @@ -226,7 +225,7 @@ namespace Components { Command::Add("banClient", [](Command::Params* params) { - if (!Dvar::Var("sv_running").get()) + if (!(*Game::com_sv_running)->current.enabled) { Logger::Print("Server is not running.\n"); return; @@ -258,7 +257,7 @@ namespace Components } const auto* cl = &Game::svs_clients[num]; - if (cl->state == Game::CS_FREE) + if (cl->header.state == Game::CS_FREE) { Logger::Print("Client {} is not active\n", num); return; @@ -270,7 +269,7 @@ namespace Components Command::Add("unbanClient", [](Command::Params* params) { - if (!Dvar::Var("sv_running").get()) + if (!(*Game::com_sv_running)->current.enabled) { Logger::Print("Server is not running.\n"); return; diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 72c3836b..57a334dc 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -294,7 +294,8 @@ namespace Components Bots::Bots() { - AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); + AssertOffset(Game::client_t, bIsTestClient, 0x41AF0); + AssertOffset(Game::client_t, ping, 0x212C8); // 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\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\""); diff --git a/src/Components/Modules/Branding.cpp b/src/Components/Modules/Branding.cpp index e878e625..6f1c3fbf 100644 --- a/src/Components/Modules/Branding.cpp +++ b/src/Components/Modules/Branding.cpp @@ -5,7 +5,6 @@ namespace Components Dvar::Var Branding::CGDrawVersion; Dvar::Var Branding::CGDrawVersionX; Dvar::Var Branding::CGDrawVersionY; - Game::dvar_t** Branding::Version = reinterpret_cast(0x1AD7930); #ifdef _DEBUG constexpr auto* BUILD_TYPE = "IW4x_DEV MP"; @@ -25,12 +24,12 @@ namespace Components auto* const placement = Game::ScrPlace_GetUnsafeFullPlacement(); auto* const font = Game::UI_GetFontHandle(placement, 0, 0.583f); - const auto width = Game::UI_TextWidth((*Version)->current.string, 0, font, fontScale); + const auto width = Game::UI_TextWidth((*Game::version)->current.string, 0, font, fontScale); const auto height = Game::UI_TextHeight(font, fontScale); - Game::UI_DrawText(placement, (*Version)->current.string, maxChars, font, 1.0f - (CGDrawVersionX.get() + static_cast(width)), + Game::UI_DrawText(placement, (*Game::version)->current.string, maxChars, font, 1.0f - (CGDrawVersionX.get() + static_cast(width)), 1.0f - (CGDrawVersionY.get() + static_cast(height)), 3, 3, fontScale, shadowColor, 0); - Game::UI_DrawText(placement, (*Version)->current.string, maxChars, font, (0.0f - static_cast(width)) - CGDrawVersionX.get(), + Game::UI_DrawText(placement, (*Game::version)->current.string, maxChars, font, (0.0f - static_cast(width)) - CGDrawVersionX.get(), (0.0f - static_cast(height)) - CGDrawVersionY.get(), 3, 3, fontScale, color, 0); } diff --git a/src/Components/Modules/Branding.hpp b/src/Components/Modules/Branding.hpp index b8424ae4..f70fdcdd 100644 --- a/src/Components/Modules/Branding.hpp +++ b/src/Components/Modules/Branding.hpp @@ -14,7 +14,6 @@ namespace Components static Dvar::Var CGDrawVersion; static Dvar::Var CGDrawVersionX; static Dvar::Var CGDrawVersionY; - static Game::dvar_t** Version; static void CG_DrawVersion(); static void CG_DrawVersion_Hk(int localClientNum); diff --git a/src/Components/Modules/Bullet.cpp b/src/Components/Modules/Bullet.cpp index fe18981a..03f9f311 100644 --- a/src/Components/Modules/Bullet.cpp +++ b/src/Components/Modules/Bullet.cpp @@ -7,10 +7,10 @@ namespace Components float Bullet::BG_GetSurfacePenetrationDepthStub(const Game::WeaponDef* weapDef, int surfaceType) { - assert(weapDef != nullptr); - assert(weapDef->penetrateType != Game::PenetrateType::PENETRATE_TYPE_NONE); - assert(weapDef->penetrateType < Game::PenetrateType::PENETRATE_TYPE_COUNT); - assert(static_cast(surfaceType) < Game::materialSurfType_t::SURF_TYPE_COUNT); + assert(weapDef); + assert(weapDef->penetrateType != Game::PENETRATE_TYPE_NONE); + AssertIn(weapDef->penetrateType, Game::PENETRATE_TYPE_COUNT); + AssertIn(surfaceType, Game::SURF_TYPE_COUNT); const auto penetrationDepth = BGSurfacePenetration.get(); if (penetrationDepth > 0.0f) diff --git a/src/Components/Modules/CardTitles.cpp b/src/Components/Modules/CardTitles.cpp index 7f5d6164..da34aa24 100644 --- a/src/Components/Modules/CardTitles.cpp +++ b/src/Components/Modules/CardTitles.cpp @@ -160,7 +160,7 @@ namespace Components { char playerTitle[18]; - if (Game::svs_clients[i].state >= Game::CS_CONNECTED) + if (Game::svs_clients[i].header.state >= Game::CS_CONNECTED) { strncpy_s(playerTitle, Game::Info_ValueForKey(Game::svs_clients[i].userinfo, "customTitle"), _TRUNCATE); } diff --git a/src/Components/Modules/Ceg.cpp b/src/Components/Modules/Ceg.cpp index 4941656c..e3fe59bc 100644 --- a/src/Components/Modules/Ceg.cpp +++ b/src/Components/Modules/Ceg.cpp @@ -46,6 +46,9 @@ namespace Components Utils::Hook::Set(0x432180, 0xC3); Utils::Hook::Set(0x461930, 0xC3); + // Used next to file system functions + Utils::Hook::Set(0x47BC00, 0xC3); + // Looking for stuff in the registry Utils::Hook::Nop(0x4826F8, 5); diff --git a/src/Components/Modules/Chat.cpp b/src/Components/Modules/Chat.cpp index 37c55e37..45ee250c 100644 --- a/src/Components/Modules/Chat.cpp +++ b/src/Components/Modules/Chat.cpp @@ -5,14 +5,14 @@ namespace Components { Dvar::Var Chat::cg_chatWidth; Dvar::Var Chat::sv_disableChat; + Dvar::Var Chat::sv_sayName; Game::dvar_t** Chat::cg_chatHeight = reinterpret_cast(0x7ED398); Game::dvar_t** Chat::cg_chatTime = reinterpret_cast(0x9F5DE8); bool Chat::SendChat; - std::mutex Chat::AccessMutex; - std::unordered_set Chat::MuteList; + Utils::Concurrency::Container Chat::MutedList; bool Chat::CanAddCallback = true; std::vector Chat::SayCallbacks; @@ -36,21 +36,13 @@ namespace Components ++text; } - std::unique_lock lock(AccessMutex); - if (MuteList.contains(Game::svs_clients[player->s.number].steamID)) + if (IsMuted(player)) { - lock.unlock(); SendChat = false; - Game::SV_GameSendServerCommand(player->s.number, Game::SV_CMD_CAN_IGNORE, + Game::SV_GameSendServerCommand(player - Game::g_entities, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"You are muted\"", 0x65)); } - // Test whether the lock is still locked - if (lock.owns_lock()) - { - lock.unlock(); - } - for (const auto& callback : SayCallbacks) { if (!ChatCallback(player, callback.getPos(), (text + 1), mode)) @@ -62,7 +54,7 @@ namespace Components if (sv_disableChat.get()) { SendChat = false; - Game::SV_GameSendServerCommand(player->s.number, Game::SV_CMD_CAN_IGNORE, + Game::SV_GameSendServerCommand(player - Game::g_entities, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"Chat is disabled\"", 0x65)); } @@ -243,25 +235,30 @@ namespace Components } } + bool Chat::IsMuted(const Game::gentity_s* ent) + { + const auto clientNum = ent - Game::g_entities; + const auto xuid = Game::svs_clients[clientNum].steamID; + + const auto result = MutedList.access([&](muteList& clients) + { + return clients.contains(xuid); + }); + + return result; + } + void Chat::MuteClient(const Game::client_t* client) { - std::unique_lock lock(AccessMutex); - - if (!MuteList.contains(client->steamID)) + const auto xuid = client->steamID; + MutedList.access([&](muteList& clients) { - MuteList.insert(client->steamID); - lock.unlock(); + clients.insert(xuid); + }); - Logger::Print("{} was muted\n", client->name); - Game::SV_GameSendServerCommand(client->gentity->s.number, Game::SV_CMD_CAN_IGNORE, - Utils::String::VA("%c \"You were muted\"", 0x65)); - return; - } - - lock.unlock(); - Logger::Print("{} is already muted\n", client->name); - Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, - Utils::String::VA("%c \"%s is already muted\"", 0x65, client->name)); + Logger::Print("{} was muted\n", client->name); + Game::SV_GameSendServerCommand(client - Game::svs_clients, Game::SV_CMD_CAN_IGNORE, + Utils::String::VA("%c \"You were muted\"", 0x65)); } void Chat::UnmuteClient(const Game::client_t* client) @@ -269,25 +266,26 @@ namespace Components UnmuteInternal(client->steamID); Logger::Print("{} was unmuted\n", client->name); - Game::SV_GameSendServerCommand(client->gentity->s.number, Game::SV_CMD_CAN_IGNORE, + Game::SV_GameSendServerCommand(client - Game::svs_clients, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"You were unmuted\"", 0x65)); } void Chat::UnmuteInternal(const std::uint64_t id, bool everyone) { - std::unique_lock lock(AccessMutex); - - if (everyone) - MuteList.clear(); - else - MuteList.erase(id); + MutedList.access([&](muteList& clients) + { + if (everyone) + clients.clear(); + else + clients.erase(id); + }); } void Chat::AddChatCommands() { Command::AddSV("muteClient", [](Command::Params* params) { - if (!Dvar::Var("sv_running").get()) + if (!(*Game::com_sv_running)->current.enabled) { Logger::Print("Server is not running.\n"); return; @@ -303,13 +301,14 @@ namespace Components const auto* client = Game::SV_GetPlayerByNum(); if (client != nullptr) { + Voice::SV_MuteClient(client - Game::svs_clients); MuteClient(client); } }); Command::AddSV("unmute", [](Command::Params* params) { - if (!Dvar::Var("sv_running").get()) + if (!(*Game::com_sv_running)->current.enabled) { Logger::Print("Server is not running.\n"); return; @@ -327,6 +326,7 @@ namespace Components if (client != nullptr) { UnmuteClient(client); + Voice::SV_UnmuteClient(client - Game::svs_clients); return; } @@ -334,6 +334,7 @@ namespace Components { Logger::Print("All players were unmuted\n"); UnmuteInternal(0, true); + Voice::SV_ClearMutedList(); } else { @@ -341,6 +342,66 @@ namespace Components UnmuteInternal(steamId); } }); + + Command::AddSV("say", [](Command::Params* params) + { + if (params->size() < 2) return; + + auto message = params->join(1); + auto name = sv_sayName.get(); + + if (!name.empty()) + { + Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s: %s\"", 0x68, name.data(), message.data())); + Logger::Print(Game::CON_CHANNEL_SERVER, "{}: {}\n", name, message); + } + else + { + Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"Console: %s\"", 0x68, message.data())); + Logger::Print(Game::CON_CHANNEL_SERVER, "Console: {}\n", message); + } + }); + + Command::AddSV("tell", [](Command::Params* params) + { + if (params->size() < 3) return; + + const auto client = std::atoi(params->get(1)); + auto message = params->join(2); + auto name = sv_sayName.get(); + + if (!name.empty()) + { + Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s: %s\"", 0x68, name.data(), message.data())); + Logger::Print(Game::CON_CHANNEL_SERVER, "{} -> {}: {}\n", name, client, message); + } + else + { + Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"Console: %s\"", 104, message.data())); + Logger::Print(Game::CON_CHANNEL_SERVER, "Console -> {}: {}\n", client, message); + } + }); + + Command::AddSV("sayraw", [](Command::Params* params) + { + if (params->size() < 2) return; + + auto message = params->join(1); + Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 0x68, message.data())); + Logger::Print(Game::CON_CHANNEL_SERVER, "Raw: {}\n", message); + }); + + Command::AddSV("tellraw", [](Command::Params* params) + { + if (params->size() < 3) return; + + const auto client = atoi(params->get(1)); + std::string message = params->join(2); + Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 0x68, message.data())); + Logger::Print(Game::CON_CHANNEL_SERVER, "Raw -> {}: {}\n", client, message); + }); + + sv_sayName = Dvar::Register("sv_sayName", "^7Console", Game::DVAR_NONE, "The alias of the server when broadcasting a chat message"); } int Chat::GetCallbackReturn() @@ -357,7 +418,7 @@ namespace Components const auto* result = &Game::scrVmPub->top[1 - Game::scrVmPub->outparamcount]; - if (result->type != Game::scrParamType_t::VAR_INTEGER) + if (result->type != Game::VAR_INTEGER) { // Garbage was returned return 1; @@ -368,14 +429,14 @@ namespace Components int Chat::ChatCallback(Game::gentity_s* self, const char* codePos, const char* message, int mode) { - const auto entityId = Game::Scr_GetEntityId(self->s.number, 0); + const auto entityId = Game::Scr_GetEntityId(self - Game::g_entities, 0); Scripting::StackIsolation _; Game::Scr_AddInt(mode); Game::Scr_AddString(message); Game::VariableValue value; - value.type = Game::scrParamType_t::VAR_OBJECT; + value.type = Game::VAR_OBJECT; value.u.uintValue = entityId; Game::AddRefToValue(value.type, value.u); @@ -410,6 +471,8 @@ namespace Components Chat::Chat() { + AssertOffset(Game::client_t, steamID, 0x43F00); + 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); diff --git a/src/Components/Modules/Chat.hpp b/src/Components/Modules/Chat.hpp index a9bd64d1..55a37738 100644 --- a/src/Components/Modules/Chat.hpp +++ b/src/Components/Modules/Chat.hpp @@ -11,6 +11,7 @@ namespace Components private: static Dvar::Var cg_chatWidth; static Dvar::Var sv_disableChat; + static Dvar::Var sv_sayName; // Game dvars static Game::dvar_t** cg_chatHeight; @@ -18,8 +19,8 @@ namespace Components static bool SendChat; - static std::mutex AccessMutex; - static std::unordered_set MuteList; + using muteList = std::unordered_set; + static Utils::Concurrency::Container MutedList; static bool CanAddCallback; // ClientCommand & GSC thread are the same static std::vector SayCallbacks; @@ -33,9 +34,10 @@ namespace Components static void CG_AddToTeamChat(const char* text); static void CG_AddToTeamChat_Stub(); + static bool IsMuted(const Game::gentity_s* ent); static void MuteClient(const Game::client_t* client); static void UnmuteClient(const Game::client_t* client); - static void UnmuteInternal(const std::uint64_t id, bool everyone = false); + static void UnmuteInternal(std::uint64_t id, bool everyone = false); static void AddChatCommands(); static int GetCallbackReturn(); diff --git a/src/Components/Modules/ClanTags.cpp b/src/Components/Modules/ClanTags.cpp index c3247f2b..a4074736 100644 --- a/src/Components/Modules/ClanTags.cpp +++ b/src/Components/Modules/ClanTags.cpp @@ -9,7 +9,7 @@ namespace Components const char* ClanTags::GetClanTagWithName(int clientNum, const char* playerName) { - assert(static_cast(clientNum) < Game::MAX_CLIENTS); + AssertIn(clientNum, Game::MAX_CLIENTS); if (ClientState[clientNum][0] == '\0') { @@ -96,7 +96,7 @@ namespace Components char* ClanTags::GamerProfile_GetClanName(int controllerIndex) { - assert(static_cast(controllerIndex) < Game::MAX_LOCAL_CLIENTS); + AssertIn(controllerIndex, Game::MAX_LOCAL_CLIENTS); assert(ClanName); CL_SanitizeClanName(); @@ -115,7 +115,7 @@ namespace Components void ClanTags::ClientUserinfoChanged(const char* s, int clientNum) { - assert(static_cast(clientNum) < Game::MAX_CLIENTS); + AssertIn(clientNum, Game::MAX_CLIENTS); auto* clanAbbrev = Game::Info_ValueForKey(s, "clanAbbrev"); @@ -224,7 +224,7 @@ namespace Components Game::PlayerCardData* ClanTags::PlayerCards_GetLiveProfileDataForController_Stub(const unsigned int controllerIndex) { auto* result = Utils::Hook::Call(0x463B90)(controllerIndex); - // controllerIndex should always be 0 + AssertIn(controllerIndex, Game::MAX_LOCAL_CLIENTS); Game::I_strncpyz(result->clanAbbrev, GamerProfile_GetClanName(static_cast(controllerIndex)), sizeof(Game::PlayerCardData::clanAbbrev)); return result; diff --git a/src/Components/Modules/ClanTags.hpp b/src/Components/Modules/ClanTags.hpp index 1893d620..7f3aec77 100644 --- a/src/Components/Modules/ClanTags.hpp +++ b/src/Components/Modules/ClanTags.hpp @@ -28,8 +28,6 @@ namespace Components static void Dvar_InfoString_Stub(char* s, const char* key, const char* value); - static void SetCachedPlayerData(int clientNum); - static void ClientUserinfoChanged(const char* s, int clientNum); static void ClientUserinfoChanged_Stub(); diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index fb052c94..ec316bed 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -3,13 +3,13 @@ namespace Components { - std::unordered_map> ClientCommand::HandlersSV; + std::unordered_map> ClientCommand::HandlersSV; bool ClientCommand::CheatsOk(const Game::gentity_s* ent) { const auto entNum = ent->s.number; - if (!Dvar::Var("sv_cheats").get()) + if (!(*Game::g_cheats)->current.enabled) { Logger::Debug("Cheats are disabled!"); Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"GAME_CHEATSNOTENABLED\"", 0x65)); @@ -26,11 +26,11 @@ namespace Components return true; } - void ClientCommand::Add(const char* name, const std::function& callback) + void ClientCommand::Add(const char* name, const std::function& callback) { const auto command = Utils::String::ToLower(name); - ClientCommand::HandlersSV[command] = callback; + HandlersSV[command] = callback; } void ClientCommand::ClientCommandStub(const int clientNum) @@ -57,9 +57,9 @@ namespace Components void ClientCommand::AddCheatCommands() { - ClientCommand::Add("noclip", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("noclip", [](Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { - if (!ClientCommand::CheatsOk(ent)) + if (!CheatsOk(ent)) return; ent->client->flags ^= Game::PLAYER_FLAG_NOCLIP; @@ -71,9 +71,9 @@ namespace Components (ent->client->flags & Game::PLAYER_FLAG_NOCLIP) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF")); }); - ClientCommand::Add("ufo", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("ufo", [](Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { - if (!ClientCommand::CheatsOk(ent)) + if (!CheatsOk(ent)) return; ent->client->flags ^= Game::PLAYER_FLAG_UFO; @@ -85,9 +85,9 @@ namespace Components (ent->client->flags & Game::PLAYER_FLAG_UFO) ? "GAME_UFOON" : "GAME_UFOOFF")); }); - ClientCommand::Add("god", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("god", [](Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { - if (!ClientCommand::CheatsOk(ent)) + if (!CheatsOk(ent)) return; ent->flags ^= Game::FL_GODMODE; @@ -99,9 +99,9 @@ namespace Components (ent->flags & Game::FL_GODMODE) ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF")); }); - ClientCommand::Add("demigod", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("demigod", [](Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { - if (!ClientCommand::CheatsOk(ent)) + if (!CheatsOk(ent)) return; ent->flags ^= Game::FL_DEMI_GODMODE; @@ -113,9 +113,9 @@ namespace Components (ent->flags & Game::FL_DEMI_GODMODE) ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF")); }); - ClientCommand::Add("notarget", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("notarget", [](Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { - if (!ClientCommand::CheatsOk(ent)) + if (!CheatsOk(ent)) return; ent->flags ^= Game::FL_NOTARGET; @@ -127,11 +127,11 @@ namespace Components (ent->flags & Game::FL_NOTARGET) ? "GAME_NOTARGETON" : "GAME_NOTARGETOFF")); }); - ClientCommand::Add("setviewpos", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("setviewpos", [](Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { assert(ent != nullptr); - if (!ClientCommand::CheatsOk(ent)) + if (!CheatsOk(ent)) return; Game::vec3_t origin, angles{0.f, 0.f, 0.f}; @@ -163,9 +163,9 @@ namespace Components Game::TeleportPlayer(ent, origin, angles); }); - ClientCommand::Add("give", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("give", [](Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { - if (!ClientCommand::CheatsOk(ent)) + if (!CheatsOk(ent)) return; if (params->size() < 2) @@ -236,38 +236,55 @@ namespace Components for (std::size_t i = 0; i < std::extent_v; ++i) { const auto index = ent->client->ps.weaponsEquipped[i]; - if (index != 0) + if (index) { Game::Add_Ammo(ent, index, 0, 998, 1); } } }); + + Add("kill", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) + { + assert(ent->client != nullptr); + assert(ent->client->sess.connected != Game::CON_DISCONNECTED); + + if (ent->client->sess.sessionState != Game::SESS_STATE_PLAYING || !CheatsOk(ent)) + return; + + Scheduler::Once([ent] + { + ent->flags &= ~(Game::FL_GODMODE | Game::FL_DEMI_GODMODE); + ent->health = 0; + ent->client->ps.stats[0] = 0; + Game::player_die(ent, ent, ent, 100000, Game::MOD_SUICIDE, 0, nullptr, Game::HITLOC_NONE, 0); + }, Scheduler::Pipeline::SERVER); + }); } void ClientCommand::AddDevelopmentCommands() { - ClientCommand::Add("dropallbots", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("dropallbots", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { Game::SV_DropAllBots(); }); - ClientCommand::Add("entitylist", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("entitylist", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { Game::Svcmd_EntityList_f(); }); - ClientCommand::Add("printentities", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("printentities", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { Game::G_PrintEntities(); }); - ClientCommand::Add("entitycount", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("entitycount", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { Logger::Print("Entity count = {}\n", Game::level->num_entities); }); // Also known as: "vis" - ClientCommand::Add("visionsetnaked", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("visionsetnaked", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { if (params->size() < 2) { @@ -295,7 +312,7 @@ namespace Components Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); }); - ClientCommand::Add("visionsetnight", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("visionsetnight", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { if (params->size() < 2) { @@ -323,7 +340,7 @@ namespace Components Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); }); - ClientCommand::Add("g_testCmd", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("g_testCmd", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { assert(ent != nullptr); @@ -331,21 +348,14 @@ namespace Components Logger::Debug("playerState_s.stunTime is {}", ent->client->ps.stunTime); }); - ClientCommand::Add("kill", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) + Add("dumpEntInfo", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) { - assert(ent->client != nullptr); - assert(ent->client->sess.connected != Game::CON_DISCONNECTED); + G_DumpEntityDebugInfoToConsole(false); + }); - if (ent->client->sess.sessionState != Game::SESS_STATE_PLAYING || !ClientCommand::CheatsOk(ent)) - return; - - Scheduler::Once([ent] - { - ent->flags &= ~(Game::FL_GODMODE | Game::FL_DEMI_GODMODE); - ent->health = 0; - ent->client->ps.stats[0] = 0; - Game::player_die(ent, ent, ent, 100000, 12, 0, nullptr, Game::HITLOC_NONE, 0); - }, Scheduler::Pipeline::SERVER); + Add("dumpEntInfoCSV", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) + { + G_DumpEntityDebugInfoToCSV(""); }); } @@ -357,15 +367,123 @@ namespace Components }); } + const char* ClientCommand::EntInfoLine(const int entNum) + { + const auto* ent = &Game::g_entities[entNum]; + + Game::XModel* model = nullptr; + if (ent->model) + { + model = Game::G_GetModel(ent->model); + } + + Game::vec3_t point, angles; + + point[0] = ent->r.currentOrigin[0] - (*Game::viewposNow)->current.vector[0]; + point[1] = ent->r.currentOrigin[1] - (*Game::viewposNow)->current.vector[1]; + point[2] = ent->r.currentOrigin[2] - (*Game::viewposNow)->current.vector[2]; + + angles[0] = ent->r.currentAngles[0]; + angles[1] = ent->r.currentAngles[1]; + angles[2] = ent->r.currentAngles[2]; + + const auto distance = std::sqrtf(point[0] * point[0] + point[1] * point[1] + + point[2] * point[2]); + + const auto* team = (ent->client) ? Game::CG_GetTeamName(ent->client->sess.cs.team) : ""; + + const auto* scriptLinkName = (ent->script_linkName) ? Game::SL_ConvertToString(ent->script_linkName) : ""; + + const auto* target = (ent->target) ? Game::SL_ConvertToString(ent->target) : ""; + + const auto* targetName = (ent->targetname) ? Game::SL_ConvertToString(ent->targetname) : ""; + + const auto* codeClassname = (ent->script_classname) ? Game::SL_ConvertToString(ent->script_classname) : ""; + + const auto* classname = (ent->classname) ? Game::SL_ConvertToString(ent->classname) : ""; + + const auto* eventType = (ent->s.eType < Game::ET_EVENTS) ? Game::G_GetEntityTypeName(ent) : ""; + + // See description of the format string in the function G_DumpEntityDebugInfoToCSV + // If empty it means the item does not exist in the current version of the game or it was not possible to reverse it + return Utils::String::VA("%i,%s,%.0f,%s,%s,%s,%s,%s,%s,%s,%s,%s,%.0f %.0f %.0f,%.0f %.0f %.0f,%i\n", + entNum, eventType, distance, classname, codeClassname, (model) ? model->name : "", + targetName, target, "", scriptLinkName, team, "", + point[0], point[1], point[2], angles[0], angles[1], angles[2], 0); + } + + void ClientCommand::G_DumpEntityDebugInfoToConsole(bool logfileOnly) + { + const auto channel = logfileOnly ? Game::CON_CHANNEL_LOGFILEONLY : Game::CON_CHANNEL_SERVER; + + Logger::Print(channel, "=====================================================================================\n"); + Logger::Print(channel, "============(entity dump begin)\n"); + Logger::Print(channel, + "Number,Type,Distance,Classname,Code Classname,Model," + "Targetname,Target,Script Noteworthy,Script Linkname,Team,ParentNum,Origin,Angles,SentToClients\n"); + + for (auto i = 0; i < Game::MAX_GENTITIES; ++i) + { + if (&Game::g_entities[i] == nullptr) + { + continue; + } + + const auto* line = EntInfoLine(i); + assert(line); + Logger::Print(channel, "%s", line); + } + + Logger::Print(channel, "(end entity dump)============\n"); + Logger::Print(channel, "=====================================================================================\n"); + } + + void ClientCommand::G_DumpEntityDebugInfoToCSV(const char* filenameSuffix) + { + assert(filenameSuffix); + + const auto* fileName = Utils::String::VA("%s%s%s%s", "EntInfo", (*filenameSuffix) ? "_" : "", filenameSuffix, ".csv"); + Logger::Print(Game::CON_CHANNEL_SERVER, "Opening file \"{}\" for writing.\n", fileName); + + auto h = Game::FS_FOpenTextFileWrite(fileName); + if (!h) + { + Logger::PrintError(Game::CON_CHANNEL_SERVER, "Couldn't open file \"{}\" for writing.\n", fileName); + return; + } + + Game::FS_Write("Number,Type,Distance,Classname,Code Classname,Model,Targetname,Target,Script Noteworthy,Script Linkname,Team,Paren" + "tNum,Origin,Angles,SentToClients\n", 147, h); + + for (auto i = 0; i < Game::MAX_GENTITIES; ++i) + { + if (&Game::g_entities[i] == nullptr) + { + continue; + } + + const auto* line = EntInfoLine(i); + const auto lineLen = std::strlen(line); + assert(line); + assert(lineLen); + Game::FS_Write(line, lineLen, h); + } + + Game::FS_FCloseFile(h); + Logger::Print(Game::CON_CHANNEL_SERVER, "Done writing file.\n"); + } + ClientCommand::ClientCommand() { - // Hook call to ClientCommand in SV_ExecuteClientCommand so we may add custom commands - Utils::Hook(0x6259FA, ClientCommand::ClientCommandStub, HOOK_CALL).install()->quick(); + AssertOffset(Game::playerState_s, stats, 0x150); - ClientCommand::AddCheatCommands(); - ClientCommand::AddScriptFunctions(); + // Hook call to ClientCommand in SV_ExecuteClientCommand so we may add custom commands + Utils::Hook(0x6259FA, ClientCommandStub, HOOK_CALL).install()->quick(); + + AddCheatCommands(); + AddScriptFunctions(); #ifdef _DEBUG - ClientCommand::AddDevelopmentCommands(); + AddDevelopmentCommands(); #endif } } diff --git a/src/Components/Modules/ClientCommand.hpp b/src/Components/Modules/ClientCommand.hpp index 60019358..554a9c26 100644 --- a/src/Components/Modules/ClientCommand.hpp +++ b/src/Components/Modules/ClientCommand.hpp @@ -7,15 +7,19 @@ namespace Components public: ClientCommand(); - static void Add(const char* name, const std::function& callback); + static void Add(const char* name, const std::function& callback); static bool CheatsOk(const Game::gentity_s* ent); private: - static std::unordered_map> HandlersSV; + static std::unordered_map> HandlersSV; static void ClientCommandStub(int clientNum); static void AddCheatCommands(); static void AddDevelopmentCommands(); static void AddScriptFunctions(); + + static const char* EntInfoLine(int entNum); + static void G_DumpEntityDebugInfoToConsole(bool logfileOnly); + static void G_DumpEntityDebugInfoToCSV(const char* filenameSuffix); }; } diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp index 0df8ec9c..af2327e6 100644 --- a/src/Components/Modules/Command.cpp +++ b/src/Components/Modules/Command.cpp @@ -5,7 +5,7 @@ namespace Components std::unordered_map> Command::FunctionMap; std::unordered_map> Command::FunctionMapSV; - std::string Command::Params::join(const int index) + std::string Command::Params::join(const int index) const { std::string result; @@ -24,12 +24,12 @@ namespace Components assert(Game::cmd_args->nesting < Game::CMD_MAX_NESTING); } - int Command::ClientParams::size() + int Command::ClientParams::size() const { return Game::cmd_args->argc[this->nesting_]; } - const char* Command::ClientParams::get(const int index) + const char* Command::ClientParams::get(const int index) const { if (index >= this->size()) { @@ -45,12 +45,12 @@ namespace Components assert(Game::sv_cmd_args->nesting < Game::CMD_MAX_NESTING); } - int Command::ServerParams::size() + int Command::ServerParams::size() const { return Game::sv_cmd_args->argc[this->nesting_]; } - const char* Command::ServerParams::get(const int index) + const char* Command::ServerParams::get(const int index) const { if (index >= this->size()) { @@ -113,7 +113,7 @@ namespace Components Game::Cmd_AddServerCommand(name, callback, Command::Allocate()); // If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler - Command::AddRaw(name, Game::Cbuf_AddServerText, false); + Command::AddRaw(name, Game::Cbuf_AddServerText_f, false); } void Command::Execute(std::string command, bool sync) diff --git a/src/Components/Modules/Command.hpp b/src/Components/Modules/Command.hpp index d6538080..9ed9889c 100644 --- a/src/Components/Modules/Command.hpp +++ b/src/Components/Modules/Command.hpp @@ -13,9 +13,9 @@ namespace Components Params() = default; virtual ~Params() = default; - virtual int size() = 0; - virtual const char* get(int index) = 0; - virtual std::string join(int index); + [[nodiscard]] virtual int size() const = 0; + [[nodiscard]] virtual const char* get(int index) const = 0; + [[nodiscard]] virtual std::string join(int index) const; virtual const char* operator[](const int index) { @@ -28,8 +28,8 @@ namespace Components public: ClientParams(); - int size() override; - const char* get(int index) override; + [[nodiscard]] int size() const override; + [[nodiscard]] const char* get(int index) const override; private: int nesting_; @@ -40,8 +40,8 @@ namespace Components public: ServerParams(); - int size() override; - const char* get(int index) override; + [[nodiscard]] int size() const override; + [[nodiscard]] const char* get(int index) const override; private: int nesting_; diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 586d0c42..8d81683b 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -24,28 +24,16 @@ namespace Components Game::SafeArea Console::OriginalSafeArea; - char** Console::GetAutoCompleteFileList(const char* path, const char* extension, Game::FsListBehavior_e behavior, int* numfiles, int allocTrackType) + const char** Console::GetAutoCompleteFileList(const char* path, const char* extension, Game::FsListBehavior_e behavior, int* numfiles, int allocTrackType) { if (path == reinterpret_cast(0xBAADF00D) || path == reinterpret_cast(0xCDCDCDCD) || ::Utils::Memory::IsBadReadPtr(path)) return nullptr; - return Game::FS_GetFileList(path, extension, behavior, numfiles, allocTrackType); - } - - void Console::ToggleConsole() - { - // possibly cls.keyCatchers? - Utils::Hook::Xor(0xB2C538, 1); - - // g_consoleField - Game::Field_Clear(reinterpret_cast(0xA1B6B0)); - - // show console output? - Utils::Hook::Set(0xA15F38, 0); + return Game::FS_ListFiles(path, extension, behavior, numfiles, allocTrackType); } void Console::RefreshStatus() { - const auto mapname = Dvar::Var("mapname").get(); - const auto hostname = TextRenderer::StripColors(Dvar::Var("sv_hostname").get()); + const std::string mapname = (*Game::sv_mapname)->current.string; + const auto hostname = TextRenderer::StripColors((*Game::sv_hostname)->current.string); if (Console::HasConsole) { @@ -58,7 +46,7 @@ namespace Components { for (int i = 0; i < maxclientCount; ++i) { - if (Game::svs_clients[i].state >= 3) + if (Game::svs_clients[i].header.state >= Game::CS_CONNECTED) { ++clientCount; } @@ -568,6 +556,9 @@ namespace Components Console::Console() { + AssertOffset(Game::clientUIActive_t, connectionState, 0x9B8); + AssertOffset(Game::clientUIActive_t, keyCatchers, 0x9B0); + // Console '%s: %s> ' string Utils::Hook::Set(0x5A44B4, "IW4x MP: " VERSION "> "); @@ -580,8 +571,8 @@ namespace Components Utils::Hook::Set(0x431565, 0xEB); // Internal console - Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).install()->quick(); - Utils::Hook(0x4F65A5, Console::ToggleConsole, HOOK_JUMP).install()->quick(); + Utils::Hook(0x4F690C, Console::Con_ToggleConsole, HOOK_CALL).install()->quick(); + Utils::Hook(0x4F65A5, Console::Con_ToggleConsole, HOOK_JUMP).install()->quick(); // Patch safearea for ingame-console Utils::Hook(0x5A50EF, Console::DrawSolidConsoleStub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Console.hpp b/src/Components/Modules/Console.hpp index baee794c..f7aa6e7b 100644 --- a/src/Components/Modules/Console.hpp +++ b/src/Components/Modules/Console.hpp @@ -63,8 +63,7 @@ namespace Components static void StoreSafeArea(); static void RestoreSafeArea(); - static void ToggleConsole(); - static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); + static const char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); static void Con_ToggleConsole(); static void AddConsoleCommand(); diff --git a/src/Components/Modules/Debug.cpp b/src/Components/Modules/Debug.cpp index 9a2fc119..a14983c5 100644 --- a/src/Components/Modules/Debug.cpp +++ b/src/Components/Modules/Debug.cpp @@ -2,7 +2,8 @@ namespace Components { - Dvar::Var Debug::DebugOverlay; + const Game::dvar_t* Debug::DebugOverlay; + const Game::dvar_t* Debug::BugName; Game::dvar_t** Debug::PlayerDebugHealth = reinterpret_cast(0x7A9F7C); @@ -90,6 +91,16 @@ namespace Components "EF_SOFT", }; + const char Debug::strButtons[] = + { + '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x0E', '\x0F', '\x10', + '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\0' + }; + + const char Debug::strTemplate[] = "%s: %s All those moments will be lost in time, like tears in rain."; + + const float Debug::colorWhite[] = {1.0f, 1.0f, 1.0f, 1.0f}; + std::string Debug::BuildPMFlagsString(const Game::playerState_s* ps) { std::string result; @@ -144,7 +155,6 @@ namespace Components auto* const scrPlace = Game::ScrPlace_GetActivePlacement(localClientNum); constexpr auto maxChars = 4096; - constexpr float colorWhite[] = {1.0f, 1.0f, 1.0f, 1.0f}; auto* const font1 = Game::UI_GetFontHandle(scrPlace, 6, MY_SCALE_2); auto* const font2 = Game::UI_GetFontHandle(scrPlace, 6, MY_SCALE2); @@ -153,16 +163,16 @@ namespace Components MY_SCALE2, colorWhite, 1); const auto pmf = BuildPMFlagsString(&cgameGlob->predictedPlayerState); - Game::UI_DrawText(scrPlace, pmf.data(), maxChars, font1, 30.0f, 20.0f, 1, 1, MY_SCALE_2, colorWhite, 3); + Game::UI_DrawText(scrPlace, pmf.data(), maxChars, font1, 30.0f, MY_Y, 1, 1, MY_SCALE_2, colorWhite, 3); const auto pof = BuildPOFlagsString(&cgameGlob->predictedPlayerState); - Game::UI_DrawText(scrPlace, pof.data(), maxChars, font1, 350.0f, 20.0f, 1, 1, MY_SCALE_2, colorWhite, 3); + Game::UI_DrawText(scrPlace, pof.data(), maxChars, font1, 350.0f, MY_Y, 1, 1, MY_SCALE_2, colorWhite, 3); const auto plf = BuildPLFlagsString(&cgameGlob->predictedPlayerState); Game::UI_DrawText(scrPlace, plf.data(), maxChars, font1, 350.0f, 250.0f, 1, 1, MY_SCALE_2, colorWhite, 3); const auto pef = BuildPEFlagsString(&cgameGlob->predictedPlayerState); - Game::UI_DrawText(scrPlace, pef.data(), maxChars, font1, 525.0f, 20.0f, 1, 1, MY_SCALE_2, colorWhite, 3); + Game::UI_DrawText(scrPlace, pef.data(), maxChars, font1, 525.0f, MY_Y, 1, 1, MY_SCALE_2, colorWhite, 3); } void Debug::CG_DrawDebugPlayerHealth(const int localClientNum) @@ -196,13 +206,49 @@ namespace Components Game::CL_DrawStretchPic(scrPlace, 10.0f, 10.0f, 100.0f * healtha, 10.0f, 1, 1, 0.0f, 0.0f, healtha, 1.0f, color2, *Game::whiteMaterial); } + void Debug::CG_Debug_DrawFontTest(const int localClientNum) + { + char strFinal[0x200]{}; + + auto* const scrPlace = Game::ScrPlace_GetActivePlacement(localClientNum); + + auto* const font1 = Game::UI_GetFontHandle(scrPlace, 1, 0.4f); + auto* const font2 = Game::UI_GetFontHandle(scrPlace, 2, 0.4f); + auto* const font3 = Game::UI_GetFontHandle(scrPlace, 3, 0.4f); + auto* const font5 = Game::UI_GetFontHandle(scrPlace, 5, 0.4f); + auto* const font6 = Game::UI_GetFontHandle(scrPlace, 6, 0.4f); + + sprintf_s(strFinal, strTemplate, font1->fontName, strButtons); + Game::UI_FilterStringForButtonAnimation(strFinal, sizeof(strFinal)); + Game::UI_DrawText(scrPlace, strFinal, std::numeric_limits::max(), font1, MY_X, 10.0f, 1, 1, 0.4f, colorWhite, 3); + + sprintf_s(strFinal, strTemplate, font2->fontName, strButtons); + Game::UI_FilterStringForButtonAnimation(strFinal, sizeof(strFinal)); + Game::UI_DrawText(scrPlace, strFinal, std::numeric_limits::max(), font2, MY_X, 35.0f, 1, 1, 0.4f, colorWhite, 3); + + sprintf_s(strFinal, strTemplate, font3->fontName, strButtons); + Game::UI_FilterStringForButtonAnimation(strFinal, sizeof(strFinal)); + Game::UI_DrawText(scrPlace, strFinal, std::numeric_limits::max(), font3, MY_X, 60.0f, 1, 1, 0.4f, colorWhite, 3); + + sprintf_s(strFinal, strTemplate, font5->fontName, strButtons); + Game::UI_FilterStringForButtonAnimation(strFinal, sizeof(strFinal)); + Game::UI_DrawText(scrPlace, strFinal, std::numeric_limits::max(), font5, MY_X, 85.0f, 1, 1, 0.4f, colorWhite, 3); + + sprintf_s(strFinal, strTemplate, font6->fontName, strButtons); + Game::UI_FilterStringForButtonAnimation(strFinal, sizeof(strFinal)); + Game::UI_DrawText(scrPlace, strFinal, std::numeric_limits::max(), font6, MY_X, 110.0f, 1, 1, 0.4f, colorWhite, 3); + } + void Debug::CG_DrawDebugOverlays_Hk(const int localClientNum) { - switch (DebugOverlay.get()) + switch (DebugOverlay->current.integer) { case 2: CG_Debug_DrawPSFlags(localClientNum); break; + case 5: + CG_Debug_DrawFontTest(localClientNum); + break; default: break; } @@ -215,7 +261,57 @@ namespace Components void Debug::Com_Assert_f() { - assert(("a", false)); + assert(0 && "a"); + } + + void Debug::Cbuf_AddServerText_f_Hk() + { + assert(0 && "Cbuf_AddServerText_f was called."); + } + + void Debug::Com_Bug_f(Command::Params* params) + { + char newFileName[0x105]{}; + char to_ospath[MAX_PATH]{}; + char from_ospath[MAX_PATH]{}; + const char* bug; + + if (!*Game::logfile) + { + Logger::PrintError(Game::CON_CHANNEL_ERROR, "CopyFile failed: logfile wasn't opened\n"); + } + + if (params->size() == 2) + { + bug = params->get(1); + } + else + { + assert(BugName); + bug = BugName->current.string; + } + + sprintf_s(newFileName, "%s_%s.log", bug, Game::Live_GetLocalClientName(0)); + + Game::Sys_EnterCriticalSection(Game::CRITSECT_CONSOLE); + + if (*Game::logfile) + { + Game::FS_FCloseFile(*Game::logfile); + *Game::logfile = 0; + } + + Game::FS_BuildOSPath(Game::Sys_DefaultInstallPath(), "", "logs/console_mp.log", from_ospath); + Game::FS_BuildOSPath(Game::Sys_DefaultInstallPath(), "", newFileName, to_ospath); + const auto result = CopyFileA(from_ospath, to_ospath, 0); + Game::Com_OpenLogFile(); + + Game::Sys_LeaveCriticalSection(Game::CRITSECT_CONSOLE); + + if (!result) + { + Logger::PrintError(1, "CopyFile failed({}) {} {}\n", GetLastError(), "console_mp.log", newFileName); + } } void Debug::CL_InitDebugDvars() @@ -233,6 +329,8 @@ namespace Components DebugOverlay = Game::Dvar_RegisterEnum("debugOverlay", debugOverlayNames_0, 0, Game::DVAR_NONE, "Toggles the display of various debug info."); + BugName = Game::Dvar_RegisterString("bug_name", "bug0", + Game::DVAR_CHEAT | Game::DVAR_CODINFO, "Name appended to the copied console log"); } Debug::Debug() @@ -243,5 +341,10 @@ namespace Components Utils::Hook(0x49CB0A, CG_DrawDebugOverlays_Hk, HOOK_JUMP).install()->quick(); Utils::Hook::Set(0x60BCEA, Com_Assert_f); + Utils::Hook(Game::Cbuf_AddServerText_f, Cbuf_AddServerText_f_Hk, HOOK_JUMP).install()->quick(); + +#ifdef _DEBUG + Command::Add("bug", Com_Bug_f); +#endif } } diff --git a/src/Components/Modules/Debug.hpp b/src/Components/Modules/Debug.hpp index a3d9dfcf..3989f420 100644 --- a/src/Components/Modules/Debug.hpp +++ b/src/Components/Modules/Debug.hpp @@ -8,7 +8,8 @@ namespace Components Debug(); private: - static Dvar::Var DebugOverlay; + static const Game::dvar_t* DebugOverlay; + static const Game::dvar_t* BugName; // Game dvars static Game::dvar_t** PlayerDebugHealth; @@ -18,9 +19,17 @@ namespace Components static const char* PLFlagsValues[]; static const char* PEFlagsValues[]; + static const char strButtons[]; + static const char strTemplate[]; + static constexpr auto MY_SCALE2 = 0.5f; static constexpr auto MY_SCALE_2 = 0.201f; + static constexpr auto MY_X = -25.0f; + static constexpr auto MY_Y = 20.0f; + + static const float colorWhite[]; + static std::string BuildPMFlagsString(const Game::playerState_s* ps); static std::string BuildPOFlagsString(const Game::playerState_s* ps); static std::string BuildPLFlagsString(const Game::playerState_s* ps); @@ -28,10 +37,13 @@ namespace Components static void CG_Debug_DrawPSFlags(int localClientNum); static void CG_DrawDebugPlayerHealth(int localClientNum); + static void CG_Debug_DrawFontTest(int localClientNum); static void CG_DrawDebugOverlays_Hk(int localClientNum); static void Com_Assert_f(); + static void Cbuf_AddServerText_f_Hk(); + static void Com_Bug_f(Command::Params* params); static void CL_InitDebugDvars(); }; diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index e2172144..5a06bb6b 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -81,9 +81,9 @@ namespace Components { std::string list = Utils::String::VA("%c", 20); - for (int i = 0; i < 18; ++i) + for (std::size_t i = 0; i < Game::MAX_CLIENTS; ++i) { - if (Game::svs_clients[i].state >= 3) + if (Game::svs_clients[i].header.state >= 3) { list.append(Utils::String::VA(" %llX", Game::svs_clients[i].steamID)); @@ -104,12 +104,12 @@ namespace Components Scheduler::Once([] { const auto partyEnable = Dvar::Var("party_enable").get(); - auto mapname = Dvar::Var("mapname").get(); + std::string mapname = (*Game::sv_mapname)->current.string; if (!partyEnable) // Time wrapping should not occur in party servers, but yeah... { if (mapname.empty()) mapname = "mp_rust"; - Command::Execute(Utils::String::VA("map %s", mapname.data()), false); + Command::Execute(Utils::String::VA("map %s", mapname.data()), true); } }, Scheduler::Pipeline::SERVER); @@ -138,71 +138,6 @@ namespace Components return Game::Dvar_RegisterInt(dvarName, 1000, min, 1000, Game::DVAR_NONE, description); } - void Dedicated::AddDedicatedCommands() - { - // Say command - Command::AddSV("say", [](Command::Params* params) - { - if (params->size() < 2) return; - - auto message = params->join(1); - auto name = Dvar::Var("sv_sayName").get(); - - if (!name.empty()) - { - Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data())); - Logger::Print(Game::CON_CHANNEL_SERVER, "{}: {}\n", name, message); - } - else - { - Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"Console: %s\"", 104, message.data())); - Logger::Print(Game::CON_CHANNEL_SERVER, "Console: {}\n", message); - } - }); - - // Tell command - Command::AddSV("tell", [](Command::Params* params) - { - if (params->size() < 3) return; - - const auto client = atoi(params->get(1)); - auto message = params->join(2); - auto name = Dvar::Var("sv_sayName").get(); - - if (!name.empty()) - { - Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s: %s\"", 104, name.data(), message.data())); - Logger::Print(Game::CON_CHANNEL_SERVER, "{} -> {}: {}\n", name, client, message); - } - else - { - Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"Console: %s\"", 104, message.data())); - Logger::Print(Game::CON_CHANNEL_SERVER, "Console -> {}: {}\n", client, message); - } - }); - - // Sayraw command - Command::AddSV("sayraw", [](Command::Params* params) - { - if (params->size() < 2) return; - - auto message = params->join(1); - Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 104, message.data())); - Logger::Print(Game::CON_CHANNEL_SERVER, "Raw: {}\n", message); - }); - - // Tellraw command - Command::AddSV("tellraw", [](Command::Params* params) - { - if (params->size() < 3) return; - - const auto client = atoi(params->get(1)); - std::string message = params->join(2); - Game::SV_GameSendServerCommand(client, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"%s\"", 104, message.data())); - Logger::Print(Game::CON_CHANNEL_SERVER, "Raw -> {}: {}\n", client, message); - }); - } - Dedicated::Dedicated() { Dedicated::COMLogFilter = Dvar::Register("com_logFilter", true, @@ -281,12 +216,9 @@ namespace Components { Scheduler::Once([] { - Dvar::Register("sv_sayName", "^7Console", Game::DVAR_NONE, "The name to pose as for 'say' commands"); Dvar::Register("sv_motd", "", Game::DVAR_NONE, "A custom message of the day for servers"); }, Scheduler::Pipeline::MAIN); - Events::OnSVInit(Dedicated::AddDedicatedCommands); - // Post initialization point Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick(); @@ -330,7 +262,7 @@ namespace Components Scheduler::Loop([] { - if (Dvar::Var("sv_running").get()) + if ((*Game::com_sv_running)->current.enabled) { Dedicated::TransmitGuids(); } diff --git a/src/Components/Modules/Dedicated.hpp b/src/Components/Modules/Dedicated.hpp index ce4d0f43..d76d0f0a 100644 --- a/src/Components/Modules/Dedicated.hpp +++ b/src/Components/Modules/Dedicated.hpp @@ -26,7 +26,5 @@ namespace Components static void TimeWrapStub(Game::errorParm_t code, const char* message); static Game::dvar_t* Dvar_RegisterSVNetworkFps(const char* dvarName, int value, int min, int max, int flags, const char* description); - - static void AddDedicatedCommands(); }; } diff --git a/src/Components/Modules/Discovery.cpp b/src/Components/Modules/Discovery.cpp index 7c4c243d..3545ab07 100644 --- a/src/Components/Modules/Discovery.cpp +++ b/src/Components/Modules/Discovery.cpp @@ -46,37 +46,37 @@ namespace Components } }); - Network::OnPacket("discovery", [](Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnClientPacket("discovery", [](Network::Address& address, [[maybe_unused]] const std::string& data) { if (address.isSelf()) return; if (!address.isLocal()) { - Logger::Print("Received discovery request from non-local address: {}\n", address.getCString()); + Logger::Print("Received discovery request from non-local address: {}\n", address.getString()); return; } - Logger::Print("Received discovery request from {}\n", address.getCString()); + Logger::Print("Received discovery request from {}\n", address.getString()); Network::SendCommand(address, "discoveryResponse", data); }); - Network::OnPacket("discoveryResponse", [](Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnClientPacket("discoveryResponse", [](Network::Address& address, [[maybe_unused]] const std::string& data) { if (address.isSelf()) return; if (!address.isLocal()) { - Logger::Print("Received discovery response from non-local address: {}\n", address.getCString()); + Logger::Print("Received discovery response from non-local address: {}\n", address.getString()); return; } if (Utils::ParseChallenge(data) != Discovery::Challenge) { - Logger::Print("Received discovery with invalid challenge from: {}\n", address.getCString()); + Logger::Print("Received discovery with invalid challenge from: {}\n", address.getString()); return; } - Logger::Print("Received discovery response from: {}\n", address.getCString()); + Logger::Print("Received discovery response from: {}\n", address.getString()); if (ServerList::IsOfflineList()) { diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 9e3b1d5b..58e0f64c 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -5,7 +5,6 @@ namespace Components { mg_mgr Download::Mgr; Download::ClientDownload Download::CLDownload; - std::vector> Download::ScriptDownloads; std::thread Download::ServerThread; bool Download::Terminate; @@ -63,7 +62,7 @@ namespace Components download->files.clear(); std::string error; - json11::Json listData = json11::Json::parse(list, error); + nlohmann::json listData = nlohmann::json::parse(list); if (!error.empty() || !listData.is_array()) { @@ -72,8 +71,9 @@ namespace Components } download->totalBytes = 0; + nlohmann::json::array_t listDataArray = listData; - for (auto& file : listData.array_items()) + for (auto& file : listDataArray) { if (!file.is_object()) return false; @@ -84,9 +84,9 @@ namespace Components if (!hash.is_string() || !name.is_string() || !size.is_number()) return false; Download::ClientDownload::File fileEntry; - fileEntry.name = name.string_value(); - fileEntry.hash = hash.string_value(); - fileEntry.size = static_cast(size.number_value()); + fileEntry.name = name.get(); + fileEntry.hash = hash.get(); + fileEntry.size = size.get(); if (!fileEntry.name.empty()) { @@ -353,9 +353,9 @@ namespace Components // Run this on the main thread Scheduler::Once([] { - auto fsGame = Dvar::Var("fs_game"); - fsGame.set(mod); - fsGame.get()->modified = true; + Game::Dvar_SetString(*Game::fs_gameDirVar, mod.data()); + const_cast(*Game::fs_gameDirVar)->modified = true; + mod.clear(); Command::Execute("closemenu mod_download_popmenu", false); @@ -387,9 +387,9 @@ namespace Components { Game::client_t* client = &Game::svs_clients[i]; - if (client->state >= 3) + if (client->header.state >= Game::CS_CONNECTED) { - if (address.getIP().full == Network::Address(client->netchan.remoteAddress).getIP().full) + if (address.getIP().full == Network::Address(client->header.netchan.remoteAddress).getIP().full) { return client; } @@ -502,14 +502,14 @@ namespace Components // Only handle http requests if (ev != MG_EV_HTTP_REQUEST) return; - std::vector servers; + std::vector servers; // Build server list for (auto& node : Node::GetNodes()) { if (node.isValid()) { - servers.push_back(json11::Json{ node }); + servers.push_back(nlohmann::json{ node.to_json()}); } } @@ -519,7 +519,7 @@ namespace Components "Connection: close\r\n" "Access-Control-Allow-Origin: *\r\n" "\r\n" - "%s", json11::Json(servers).dump().data()); + "%s", nlohmann::json(servers).dump().data()); nc->flags |= MG_F_SEND_AND_CLOSE; } @@ -532,17 +532,17 @@ namespace Components if (!Download::VerifyPassword(nc, reinterpret_cast(ev_data))) return; static std::string mapnamePre; - static json11::Json jsonList; + static nlohmann::json jsonList; std::string mapname = (Party::IsInUserMapLobby() ? Dvar::Var("ui_mapname").get() : Maps::GetUserMap()->getName()); if (!Maps::GetUserMap()->isValid() && !Party::IsInUserMapLobby()) { mapnamePre.clear(); - jsonList = std::vector(); + jsonList = std::vector(); } else if (!mapname.empty() && mapname != mapnamePre) { - std::vector fileList; + std::vector fileList; mapnamePre = mapname; @@ -553,7 +553,7 @@ namespace Components std::string filename = path + "\\" + mapname + Maps::UserMapFiles[i]; if (Utils::IO::FileExists(filename)) { - std::map file; + std::map file; std::string fileBuffer = Utils::IO::ReadFile(filename); file["name"] = mapname + Maps::UserMapFiles[i]; @@ -591,13 +591,13 @@ namespace Components // else { static std::string fsGamePre; - static json11::Json jsonList; + static nlohmann::json jsonList; - std::string fsGame = Dvar::Var("fs_game").get(); + const std::string fsGame = (*Game::fs_gameDirVar)->current.string; if (!fsGame.empty() && fsGame != fsGamePre) { - std::vector fileList; + std::vector fileList; fsGamePre = fsGame; @@ -611,7 +611,7 @@ namespace Components std::string filename = path + "\\" + *i; if (strstr(i->data(), "_svr_") == nullptr && Utils::IO::FileExists(filename)) { - std::map file; + std::map file; std::string fileBuffer = Utils::IO::ReadFile(filename); file["name"] = *i; @@ -697,7 +697,7 @@ namespace Components } std::string file; - std::string fsGame = Dvar::Var("fs_game").get(); + const std::string fsGame = (*Game::fs_gameDirVar)->current.string; std::string path = Dvar::Var("fs_basepath").get() + "\\" + (isMap ? "" : fsGame + "\\") + url; if ((!isMap && fsGame.empty()) || !Utils::IO::ReadFile(path, &file)) @@ -735,23 +735,23 @@ namespace Components Utils::InfoString status = ServerInfo::GetInfo(); Utils::InfoString host = ServerInfo::GetHostInfo(); - std::map info; + std::map info; info["status"] = status.to_json(); info["host"] = host.to_json(); - std::vector players; + std::vector players; // Build player list for (int i = 0; i < atoi(status.get("sv_maxclients").data()); ++i) // Maybe choose 18 here? { - std::map playerInfo; + std::map playerInfo; playerInfo["score"] = 0; playerInfo["ping"] = 0; playerInfo["name"] = ""; - if (Dvar::Var("sv_running").get()) + if ((*Game::com_sv_running)->current.enabled) { - if (Game::svs_clients[i].state < 3) continue; + if (Game::svs_clients[i].header.state < Game::CS_CONNECTED) continue; playerInfo["score"] = Game::SV_GameClientNum_Score(i); playerInfo["ping"] = Game::svs_clients[i].ping; @@ -760,13 +760,13 @@ namespace Components else { // Score and ping are irrelevant - const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast(0x1081C00), i); + const char* namePtr = Game::PartyHost_GetMemberName(Game::g_lobbyData, i); if (!namePtr || !namePtr[0]) continue; playerInfo["name"] = namePtr; } - players.push_back(playerInfo); + players.emplace_back(playerInfo); } info["players"] = players; @@ -777,7 +777,7 @@ namespace Components "Connection: close\r\n" "Access-Control-Allow-Origin: *\r\n" "\r\n" - "%s", json11::Json(info).dump().data()); + "%s", nlohmann::json(info).dump().data()); nc->flags |= MG_F_SEND_AND_CLOSE; } @@ -909,7 +909,7 @@ namespace Components Dvar::Register("ui_dl_transRate", "", Game::DVAR_NONE, ""); }, Scheduler::Pipeline::MAIN); - UIScript::Add("mod_download_cancel", [](UIScript::Token) + UIScript::Add("mod_download_cancel", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { Download::CLDownload.clear(); }); @@ -926,77 +926,8 @@ namespace Components Dvar::Register("mod_force_download_server", false, Game::DVAR_ARCHIVE, "Set to true to force the client to run the download server for mods (for mods in private matches)."); }, Scheduler::Pipeline::MAIN); - Scheduler::Loop([] - { - int workingCount = 0; - - for (auto i = Download::ScriptDownloads.begin(); i != Download::ScriptDownloads.end();) - { - auto download = *i; - - if (download->isDone()) - { - download->notifyDone(); - i = Download::ScriptDownloads.erase(i); - continue; - } - - if (download->isWorking()) - { - download->notifyProgress(); - ++workingCount; - } - - ++i; - } - - for (auto& download : Download::ScriptDownloads) - { - if (workingCount > 5) break; - if (!download->isWorking()) - { - download->startWorking(); - ++workingCount; - } - } - - }, Scheduler::Pipeline::MAIN); - - Events::OnVMShutdown([] - { - Download::ScriptDownloads.clear(); - }); - - Script::AddFunction("HttpGet", [] - { - const auto* url = Game::Scr_GetString(0); - - if (url == nullptr) - { - Game::Scr_ParamError(0, "^1HttpGet: Illegal parameter!\n"); - return; - } - - auto object = Game::AllocObject(); - - Game::Scr_AddObject(object); - - Download::ScriptDownloads.push_back(std::make_shared(url, object)); - Game::RemoveRefToObject(object); - }); - - Script::AddFunction("HttpCancel", [] - { - const auto object = Game::Scr_GetObject(0); - for (const auto& download : Download::ScriptDownloads) - { - if (object == download->getObject()) - { - download->cancel(); - break; - } - } - }); + Script::AddFunction("HttpGet", Script::ShowDeprecationWarning); + Script::AddFunction("HttpCancel", Script::ShowDeprecationWarning); } Download::~Download() @@ -1019,7 +950,5 @@ namespace Components { Download::CLDownload.clear(); } - - Download::ScriptDownloads.clear(); } } diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index cf934f34..67bfb9b9 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -1,4 +1,5 @@ #pragma once +#include namespace Components { @@ -81,132 +82,8 @@ namespace Components size_t receivedBytes; }; - class ScriptDownload - { - public: - ScriptDownload(const std::string& _url, unsigned int _object) : url(_url), object(_object), webIO(nullptr), done(false), notifyRequired(false), totalSize(0), currentSize(0) - { - Game::AddRefToObject(this->getObject()); - } - - ScriptDownload(ScriptDownload&& other) noexcept = delete; - ScriptDownload& operator=(ScriptDownload&& other) noexcept = delete; - - ~ScriptDownload() - { - if (this->getObject()) - { - Game::RemoveRefToObject(this->getObject()); - this->object = 0; - } - - if (this->workerThread.joinable()) - { - this->workerThread.join(); - } - - this->destroyWebIO(); - } - - void startWorking() - { - if (!this->isWorking()) - { - this->workerThread = std::thread(std::bind(&ScriptDownload::handler, this)); - } - } - - bool isWorking() - { - return this->workerThread.joinable(); - } - - void notifyProgress() - { - if (this->notifyRequired) - { - this->notifyRequired = false; - - if (Game::Scr_IsSystemActive()) - { - Game::Scr_AddInt(static_cast(this->totalSize)); - Game::Scr_AddInt(static_cast(this->currentSize)); - Game::Scr_NotifyId(this->getObject(), Game::SL_GetString("progress", 0), 2); - } - } - } - - void updateProgress(size_t _currentSize, size_t _toalSize) - { - this->currentSize = _currentSize; - this->totalSize = _toalSize; - this->notifyRequired = true; - } - - void notifyDone() - { - if (!this->isDone()) return; - - if (Game::Scr_IsSystemActive()) - { - Game::Scr_AddString(this->result.data()); // No binary data supported yet - Game::Scr_AddInt(this->success); - Game::Scr_NotifyId(this->getObject(), Game::SL_GetString("done", 0), 2); - } - } - - bool isDone() { return this->done; }; - - std::string getUrl() { return this->url; } - unsigned int getObject() { return this->object; } - - void cancel() - { - if (this->webIO) - { - this->webIO->cancelDownload(); - } - } - - private: - std::string url; - std::string result; - unsigned int object; - std::thread workerThread; - Utils::WebIO* webIO; - - bool done; - bool success; - bool notifyRequired; - size_t totalSize; - size_t currentSize; - - void handler() - { - this->destroyWebIO(); - - this->webIO = new Utils::WebIO("IW4x"); - this->webIO->setProgressCallback(std::bind(&ScriptDownload::updateProgress, this, std::placeholders::_1, std::placeholders::_2)); - - this->result = this->webIO->get(this->url, &this->success); - - this->destroyWebIO(); - this->done = true; - } - - void destroyWebIO() - { - if (this->webIO) - { - delete this->webIO; - this->webIO = nullptr; - } - } - }; - static mg_mgr Mgr; static ClientDownload CLDownload; - static std::vector> ScriptDownloads; static std::thread ServerThread; static bool Terminate; static bool ServerRunning; diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index 4334dd59..43806d72 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -4,33 +4,33 @@ namespace Components { const char* Dvar::ArchiveDvarPath = "userraw/archivedvars.cfg"; - Dvar::Var::Var(const std::string& dvarName) : Var() + Dvar::Var::Var(const std::string& dvarName) { - this->dvar = Game::Dvar_FindVar(dvarName.data()); + this->dvar_ = Game::Dvar_FindVar(dvarName.data()); // If the dvar can't be found it will be registered as an empty string dvar - if (this->dvar == nullptr) + if (this->dvar_ == nullptr) { - this->dvar = const_cast(Game::Dvar_SetFromStringByNameFromSource(dvarName.data(), "", + this->dvar_ = const_cast(Game::Dvar_SetFromStringByNameFromSource(dvarName.data(), "", Game::DvarSetSource::DVAR_SOURCE_INTERNAL)); } } template <> Game::dvar_t* Dvar::Var::get() { - return this->dvar; + return this->dvar_; } template <> const char* Dvar::Var::get() { - if (this->dvar == nullptr) + if (this->dvar_ == nullptr) return ""; - if (this->dvar->type == Game::dvar_type::DVAR_TYPE_STRING - || this->dvar->type == Game::dvar_type::DVAR_TYPE_ENUM) + if (this->dvar_->type == Game::DVAR_TYPE_STRING + || this->dvar_->type == Game::DVAR_TYPE_ENUM) { - if (this->dvar->current.string != nullptr) - return this->dvar->current.string; + if (this->dvar_->current.string != nullptr) + return this->dvar_->current.string; } return ""; @@ -38,12 +38,12 @@ namespace Components template <> int Dvar::Var::get() { - if (this->dvar == nullptr) + if (this->dvar_ == nullptr) return 0; - if (this->dvar->type == Game::dvar_type::DVAR_TYPE_INT || this->dvar->type == Game::dvar_type::DVAR_TYPE_ENUM) + if (this->dvar_->type == Game::DVAR_TYPE_INT || this->dvar_->type == Game::DVAR_TYPE_ENUM) { - return this->dvar->current.integer; + return this->dvar_->current.integer; } return 0; @@ -51,12 +51,12 @@ namespace Components template <> unsigned int Dvar::Var::get() { - if (this->dvar == nullptr) + if (this->dvar_ == nullptr) return 0; - if (this->dvar->type == Game::dvar_type::DVAR_TYPE_INT) + if (this->dvar_->type == Game::DVAR_TYPE_INT) { - return this->dvar->current.unsignedInt; + return this->dvar_->current.unsignedInt; } return 0; @@ -64,12 +64,12 @@ namespace Components template <> float Dvar::Var::get() { - if (this->dvar == nullptr) + if (this->dvar_ == nullptr) return 0.f; - if (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT) + if (this->dvar_->type == Game::DVAR_TYPE_FLOAT) { - return this->dvar->current.value; + return this->dvar_->current.value; } return 0.f; @@ -79,13 +79,13 @@ namespace Components { static Game::vec4_t vector{0.f, 0.f, 0.f, 0.f}; - if (this->dvar == nullptr) + if (this->dvar_ == nullptr) return vector; - if (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_2 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_3 - || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_4) + if (this->dvar_->type == Game::DVAR_TYPE_FLOAT_2 || this->dvar_->type == Game::DVAR_TYPE_FLOAT_3 + || this->dvar_->type == Game::DVAR_TYPE_FLOAT_4) { - return this->dvar->current.vector; + return this->dvar_->current.vector; } return vector; @@ -93,12 +93,12 @@ namespace Components template <> bool Dvar::Var::get() { - if (this->dvar == nullptr) + if (this->dvar_ == nullptr) return false; - if (this->dvar->type == Game::dvar_type::DVAR_TYPE_BOOL) + if (this->dvar_->type == Game::DVAR_TYPE_BOOL) { - return this->dvar->current.enabled; + return this->dvar_->current.enabled; } return false; @@ -111,10 +111,10 @@ namespace Components void Dvar::Var::set(const char* string) { - assert(this->dvar->type == Game::DVAR_TYPE_STRING); - if (this->dvar) + assert(this->dvar_->type == Game::DVAR_TYPE_STRING); + if (this->dvar_) { - Game::Dvar_SetString(this->dvar, string); + Game::Dvar_SetString(this->dvar_, string); } } @@ -125,58 +125,64 @@ namespace Components void Dvar::Var::set(int integer) { - assert(this->dvar->type == Game::DVAR_TYPE_INT); - if (this->dvar) + assert(this->dvar_->type == Game::DVAR_TYPE_INT); + + if (this->dvar_) { - Game::Dvar_SetInt(this->dvar, integer); + Game::Dvar_SetInt(this->dvar_, integer); } } void Dvar::Var::set(float value) { - assert(this->dvar->type == Game::DVAR_TYPE_FLOAT); - if (this->dvar) + assert(this->dvar_->type == Game::DVAR_TYPE_FLOAT); + + if (this->dvar_) { - Game::Dvar_SetFloat(this->dvar, value); + Game::Dvar_SetFloat(this->dvar_, value); } } void Dvar::Var::set(bool enabled) { - assert(this->dvar->type == Game::DVAR_TYPE_BOOL); - if (this->dvar) + assert(this->dvar_->type == Game::DVAR_TYPE_BOOL); + + if (this->dvar_) { - Game::Dvar_SetBool(this->dvar, enabled); + Game::Dvar_SetBool(this->dvar_, enabled); } } void Dvar::Var::setRaw(int integer) { - assert(this->dvar->type == Game::DVAR_TYPE_INT); - if (this->dvar) + assert(this->dvar_->type == Game::DVAR_TYPE_INT); + + if (this->dvar_) { - this->dvar->current.integer = integer; - this->dvar->latched.integer = integer; + this->dvar_->current.integer = integer; + this->dvar_->latched.integer = integer; } } void Dvar::Var::setRaw(float value) { - assert(this->dvar->type == Game::DVAR_TYPE_FLOAT); - if (this->dvar) + assert(this->dvar_->type == Game::DVAR_TYPE_FLOAT); + + if (this->dvar_) { - this->dvar->current.value = value; - this->dvar->latched.value = value; + this->dvar_->current.value = value; + this->dvar_->latched.value = value; } } void Dvar::Var::setRaw(bool enabled) { - assert(this->dvar->type == Game::DVAR_TYPE_BOOL); - if (this->dvar) + assert(this->dvar_->type == Game::DVAR_TYPE_BOOL); + + if (this->dvar_) { - this->dvar->current.enabled = enabled; - this->dvar->latched.enabled = enabled; + this->dvar_->current.enabled = enabled; + this->dvar_->latched.enabled = enabled; } } diff --git a/src/Components/Modules/Dvar.hpp b/src/Components/Modules/Dvar.hpp index b457f16b..dacee8ee 100644 --- a/src/Components/Modules/Dvar.hpp +++ b/src/Components/Modules/Dvar.hpp @@ -17,9 +17,9 @@ namespace Components class Var { public: - Var() : dvar(nullptr) {} - Var(const Var& obj) { this->dvar = obj.dvar; } - Var(Game::dvar_t* _dvar) : dvar(_dvar) {} + Var() : dvar_(nullptr) {} + Var(const Var& obj) { this->dvar_ = obj.dvar_; } + Var(Game::dvar_t* dvar) : dvar_(dvar) {} Var(DWORD ppdvar) : Var(*reinterpret_cast(ppdvar)) {} Var(const std::string& dvarName); @@ -37,7 +37,7 @@ namespace Components void setRaw(bool enabled); private: - Game::dvar_t* dvar; + Game::dvar_t* dvar_; }; Dvar(); diff --git a/src/Components/Modules/FileSystem.cpp b/src/Components/Modules/FileSystem.cpp index 39816e09..473a38ac 100644 --- a/src/Components/Modules/FileSystem.cpp +++ b/src/Components/Modules/FileSystem.cpp @@ -15,21 +15,23 @@ namespace Components int handle; const auto len = Game::FS_FOpenFileReadForThread(filePath.data(), &handle, thread); - if (handle) + if (!handle) { - auto* buf = AllocateFile(len + 1); - - [[maybe_unused]] auto bytesRead = Game::FS_Read(buf, len, handle); - - assert(bytesRead == len); - - buf[len] = '\0'; - - Game::FS_FCloseFile(handle); - - this->buffer.append(buf, len); - FreeFile(buf); + return; } + + auto* buf = AllocateFile(len + 1); + + [[maybe_unused]] auto bytesRead = Game::FS_Read(buf, len, handle); + + assert(bytesRead == len); + + buf[len] = '\0'; + + Game::FS_FCloseFile(handle); + + this->buffer.append(buf, len); + FreeFile(buf); } void FileSystem::RawFile::read() @@ -138,12 +140,28 @@ namespace Components } } + std::filesystem::path FileSystem::GetAppdataPath() + { + PWSTR path; + if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path))) + { + throw std::runtime_error("Failed to read APPDATA path!"); + } + + auto _0 = gsl::finally([&path] + { + CoTaskMemFree(path); + }); + + return std::filesystem::path(path) / "xlabs"; + } + std::vector FileSystem::GetFileList(const std::string& path, const std::string& extension) { std::vector fileList; - int numFiles = 0; - char** files = Game::FS_GetFileList(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 0); + auto numFiles = 0; + const auto** files = Game::FS_ListFiles(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 10); if (files) { @@ -151,11 +169,11 @@ namespace Components { if (files[i]) { - fileList.push_back(files[i]); + fileList.emplace_back(files[i]); } } - Game::FS_FreeFileList(files); + Game::FS_FreeFileList(files, 10); } return fileList; @@ -165,8 +183,8 @@ namespace Components { std::vector fileList; - int numFiles = 0; - char** files = Game::Sys_ListFiles(path.data(), extension.data(), nullptr, &numFiles, folders); + auto numFiles = 0; + const auto** files = Game::Sys_ListFiles(path.data(), extension.data(), nullptr, &numFiles, folders); if (files) { @@ -174,7 +192,7 @@ namespace Components { if (files[i]) { - fileList.push_back(files[i]); + fileList.emplace_back(files[i]); } } @@ -184,9 +202,9 @@ namespace Components return fileList; } - bool FileSystem::DeleteFile(const std::string& folder, const std::string& file) + bool FileSystem::_DeleteFile(const std::string& folder, const std::string& file) { - char path[MAX_PATH] = { 0 }; + char path[MAX_PATH] = {0}; Game::FS_BuildPathToFile(Dvar::Var("fs_basepath").get(), reinterpret_cast(0x63D0BB8), Utils::String::VA("%s/%s", folder.data(), file.data()), reinterpret_cast(&path)); return Game::FS_Remove(path); } @@ -225,9 +243,9 @@ namespace Components void FileSystem::RegisterFolder(const char* folder) { - std::string fs_cdpath = Dvar::Var("fs_cdpath").get(); - std::string fs_basepath = Dvar::Var("fs_basepath").get(); - std::string fs_homepath = Dvar::Var("fs_homepath").get(); + const auto fs_cdpath = Dvar::Var("fs_cdpath").get(); + const auto fs_basepath = Dvar::Var("fs_basepath").get(); + const auto fs_homepath = Dvar::Var("fs_homepath").get(); if (!fs_cdpath.empty()) Game::FS_AddLocalizedGameDirectory(fs_cdpath.data(), folder); if (!fs_basepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_basepath.data(), folder); @@ -305,6 +323,12 @@ namespace Components Utils::Hook::Call(0x4291A0)(iwd); } + const char* FileSystem::Sys_DefaultInstallPath_Hk() + { + static auto current_path = std::filesystem::current_path().string(); + return current_path.data(); + } + FileSystem::FileSystem() { FileSystem::MemAllocator.clear(); @@ -352,6 +376,9 @@ namespace Components // Handle IWD freeing Utils::Hook(0x642F60, FileSystem::IwdFreeStub, HOOK_CALL).install()->quick(); + + // Set the working dir based on info from the Xlabs launcher + Utils::Hook(0x4326E0, FileSystem::Sys_DefaultInstallPath_Hk, HOOK_JUMP).install()->quick(); } FileSystem::~FileSystem() diff --git a/src/Components/Modules/FileSystem.hpp b/src/Components/Modules/FileSystem.hpp index e6c17e44..50573b40 100644 --- a/src/Components/Modules/FileSystem.hpp +++ b/src/Components/Modules/FileSystem.hpp @@ -8,7 +8,7 @@ namespace Components class AbstractFile { public: - virtual ~AbstractFile() {}; + virtual ~AbstractFile() = default; virtual bool exists() = 0; virtual std::string getName() = 0; @@ -19,12 +19,12 @@ namespace Components { public: File() = default; - File(std::string file) : filePath{std::move(file)} { this->read(); }; - File(std::string file, Game::FsThread thread) : filePath{std::move(file)} { this->read(thread); }; + File(std::string file) : filePath{std::move(file)} { this->read(); } + File(std::string file, Game::FsThread thread) : filePath{std::move(file)} { this->read(thread); } - bool exists() override { return !this->buffer.empty(); }; - std::string getName() override { return this->filePath; }; - std::string& getBuffer() override { return this->buffer; }; + bool exists() override { return !this->buffer.empty(); } + std::string getName() override { return this->filePath; } + std::string& getBuffer() override { return this->buffer; } private: std::string filePath; @@ -36,12 +36,12 @@ namespace Components class RawFile : public AbstractFile { public: - RawFile() {}; - RawFile(const std::string& file) : filePath(file) { this->read(); }; + RawFile() = default; + RawFile(std::string file) : filePath(std::move(file)) { this->read(); } - bool exists() override { return !this->buffer.empty(); }; - std::string getName() override { return this->filePath; }; - std::string& getBuffer() override { return this->buffer; }; + bool exists() override { return !this->buffer.empty(); } + std::string getName() override { return this->filePath; } + std::string& getBuffer() override { return this->buffer; } private: std::string filePath; @@ -53,7 +53,7 @@ namespace Components class FileReader { public: - FileReader() : handle(0), size(-1), name() {}; + FileReader() : handle(0), size(-1), name() {} FileReader(const std::string& file); ~FileReader(); @@ -73,8 +73,8 @@ namespace Components class FileWriter { public: - FileWriter(const std::string& file, bool append = false) : handle(0), filePath(file) { this->open(append); }; - ~FileWriter() { this->close(); }; + FileWriter(std::string file, bool append = false) : handle(0), filePath(std::move(file)) { this->open(append); } + ~FileWriter() { this->close(); } void write(const std::string& data); @@ -89,9 +89,10 @@ namespace Components FileSystem(); ~FileSystem(); + static std::filesystem::path GetAppdataPath(); static std::vector GetFileList(const std::string& path, const std::string& extension); static std::vector GetSysFileList(const std::string& path, const std::string& extension, bool folders = false); - static bool DeleteFile(const std::string& folder, const std::string& file); + static bool _DeleteFile(const std::string& folder, const std::string& file); private: static std::mutex Mutex; @@ -115,5 +116,7 @@ namespace Components static int LoadTextureSync(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image); static void IwdFreeStub(Game::iwd_t* iwd); + + static const char* Sys_DefaultInstallPath_Hk(); }; } diff --git a/src/Components/Modules/Friends.cpp b/src/Components/Modules/Friends.cpp index bb0cff57..0ace8be5 100644 --- a/src/Components/Modules/Friends.cpp +++ b/src/Components/Modules/Friends.cpp @@ -126,22 +126,14 @@ namespace Components } } - void Friends::UpdateState(bool force) + void Friends::UpdateState() { - if (Friends::CLAnonymous.get() || Friends::IsInvisible() || !Steam::Enabled()) return; + if (Friends::CLAnonymous.get() || Friends::IsInvisible() || !Steam::Enabled()) + { + return; + } - if (force) - { - if (Steam::Proxy::ClientFriends && Steam::Proxy::SteamFriends) - { - int state = Steam::Proxy::SteamFriends->GetPersonaState(); - Steam::Proxy::ClientFriends.invoke("SetPersonaState", (state == 1 ? 2 : 1)); - } - } - else - { - Friends::TriggerUpdate = true; - } + Friends::TriggerUpdate = true; } void Friends::UpdateServer(Network::Address server, const std::string& hostname, const std::string& mapname) @@ -424,14 +416,13 @@ namespace Components { return Utils::String::VA("%s", user.name.data()); } - else if (user.name == user.playerName) + + if (user.name == user.playerName) { return Utils::String::VA("%s", user.name.data()); } - else - { - return Utils::String::VA("%s ^7(%s^7)", user.name.data(), user.playerName.data()); - } + + return Utils::String::VA("%s ^7(%s^7)", user.name.data(), user.playerName.data()); } case 2: { @@ -613,12 +604,12 @@ namespace Components // Show blue icons on the minimap Utils::Hook(0x493130, Friends::IsClientInParty, HOOK_JUMP).install()->quick(); - UIScript::Add("LoadFriends", [](UIScript::Token) + UIScript::Add("LoadFriends", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { Friends::UpdateFriends(); }); - UIScript::Add("JoinFriend", [](UIScript::Token) + UIScript::Add("JoinFriend", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { std::lock_guard _(Friends::Mutex); if (Friends::CurrentFriend >= Friends::FriendsList.size()) return; @@ -660,7 +651,7 @@ namespace Components if (Friends::TriggerUpdate) { Friends::TriggerUpdate = false; - Friends::UpdateState(true); + Friends::UpdateState(); } } diff --git a/src/Components/Modules/Friends.hpp b/src/Components/Modules/Friends.hpp index d8dee9ef..4bc0075f 100644 --- a/src/Components/Modules/Friends.hpp +++ b/src/Components/Modules/Friends.hpp @@ -83,7 +83,7 @@ namespace Components static bool IsClientInParty(int controller, int clientNum); static void UpdateUserInfo(SteamID user); - static void UpdateState(bool force = false); + static void UpdateState(); static void SortList(bool force = false); static void SortIndividualList(std::vector* list); diff --git a/src/Components/Modules/GSC/GSC.cpp b/src/Components/Modules/GSC/GSC.cpp index 18de80a4..3970b014 100644 --- a/src/Components/Modules/GSC/GSC.cpp +++ b/src/Components/Modules/GSC/GSC.cpp @@ -1,5 +1,6 @@ #include +#include "Int64.hpp" #include "IO.hpp" #include "Script.hpp" #include "ScriptExtension.hpp" @@ -9,6 +10,7 @@ namespace Components { GSC::GSC() { + Loader::Register(new Int64()); Loader::Register(new IO()); Loader::Register(new Script()); Loader::Register(new ScriptExtension()); diff --git a/src/Components/Modules/GSC/Int64.cpp b/src/Components/Modules/GSC/Int64.cpp new file mode 100644 index 00000000..c2fc4eee --- /dev/null +++ b/src/Components/Modules/GSC/Int64.cpp @@ -0,0 +1,95 @@ +#include +#include "Int64.hpp" +#include "Script.hpp" + +#define INT64_OPERATION(expr) [](const std::int64_t a, [[maybe_unused]] const std::int64_t b) { return expr; } + +namespace Components +{ + std::unordered_map Int64::Operations = + { + {"+", INT64_OPERATION(a + b)}, + {"-", INT64_OPERATION(a - b)}, + {"*", INT64_OPERATION(a * b)}, + {"/", INT64_OPERATION(a / b)}, + {"&", INT64_OPERATION(a & b)}, + {"^", INT64_OPERATION(a ^ b)}, + {"|", INT64_OPERATION(a | b)}, + {"~", INT64_OPERATION(~a)}, + {"%", INT64_OPERATION(a % b)}, + {">>", INT64_OPERATION(a >> b)}, + {"<<", INT64_OPERATION(a << b)}, + {"++", INT64_OPERATION(a + 1)}, + {"--", INT64_OPERATION(a - 1)}, + }; + + std::unordered_map Int64::Comparisons + { + {">", INT64_OPERATION(a > b)}, + {">=", INT64_OPERATION(a >= b)}, + {"==", INT64_OPERATION(a == b)}, + {"<=", INT64_OPERATION(a <= b)}, + {"<", INT64_OPERATION(a < b)}, + }; + + std::int64_t Int64::GetInt64Arg(unsigned int index, bool optional) + { + if ((optional) && (index >= Game::Scr_GetNumParam())) + { + return 0; + } + + if (Game::Scr_GetType(index) == Game::VAR_INTEGER) + { + return Game::Scr_GetInt(index); + } + + if (Game::Scr_GetType(index) == Game::VAR_STRING) + { + return std::strtoll(Game::Scr_GetString(index), nullptr, 0); + } + + Game::Scr_ParamError(index, Utils::String::VA("cannot cast %s to int64", Game::Scr_GetTypeName(index))); + return 0; + } + + void Int64::AddFunctions() + { + Script::AddFunction("Int64IsInt", [] + { + const auto value = GetInt64Arg(0, false); + Game::Scr_AddBool(value <= std::numeric_limits::max() && value >= std::numeric_limits::min()); + }); + + Script::AddFunction("Int64ToInt", [] + { + Game::Scr_AddInt(static_cast(GetInt64Arg(0, false))); + }); + + Script::AddFunction("Int64OP", [] + { + const auto a = GetInt64Arg(0, false); + const auto* op = Game::Scr_GetString(1); + const auto b = GetInt64Arg(2, true); + + if (const auto got = Operations.find(op); got != Operations.end()) + { + Game::Scr_AddString(Utils::String::VA("%lld", got->second(a, b))); + return; + } + + if (const auto got = Comparisons.find(op); got != Comparisons.end()) + { + Game::Scr_AddBool(got->second(a, b)); + return; + } + + Game::Scr_ParamError(1, "Invalid int64 operation"); + }); + } + + Int64::Int64() + { + AddFunctions(); + } +} diff --git a/src/Components/Modules/GSC/Int64.hpp b/src/Components/Modules/GSC/Int64.hpp new file mode 100644 index 00000000..cbdc79f5 --- /dev/null +++ b/src/Components/Modules/GSC/Int64.hpp @@ -0,0 +1,20 @@ +#pragma once + +namespace Components +{ + class Int64 : public Component + { + public: + Int64(); + + private: + using int64_OP = std::function; + using int64_Comp = std::function; + + static std::unordered_map Operations; + static std::unordered_map Comparisons; + + static std::int64_t GetInt64Arg(unsigned int index, bool optional); + static void AddFunctions(); + }; +} diff --git a/src/Components/Modules/GSC/Script.cpp b/src/Components/Modules/GSC/Script.cpp index 683e1ede..b87c9b17 100644 --- a/src/Components/Modules/GSC/Script.cpp +++ b/src/Components/Modules/GSC/Script.cpp @@ -50,12 +50,10 @@ namespace Components void Script::RuntimeError(const char* codePos, unsigned int index, const char* msg, const char* dialogMessage) { - const auto developer = Dvar::Var("developer").get(); - // Allow error messages to be printed if developer mode is on // Should check scrVarPub.developer but it's absent // in this version of the game so let's check the dvar - if (!Game::scrVmPub->terminal_error && !developer) + if (!Game::scrVmPub->terminal_error && !(*Game::com_developer)->current.integer) return; // If were are developing let's call RuntimeErrorInternal @@ -227,42 +225,44 @@ namespace Components Game::Scr_StartupGameType(); } + // Do not use C++ objects because Scr_LoadScript may longjmp void Script::GScr_LoadGameTypeScript_Stub() { // Clear handles (from previous GSC loading session) Script::ScriptMainHandles.clear(); Script::ScriptInitHandles.clear(); - const auto list = FileSystem::GetFileList("scripts/", "gsc"); + char path[MAX_PATH]{}; - for (const auto& file : list) + auto numFiles = 0; + const auto** files = Game::FS_ListFiles("scripts/", "gsc", Game::FS_LIST_ALL, &numFiles, 10); + + for (auto i = 0; i < numFiles; ++i) { - std::string script = "scripts/" + file; + const auto* scriptFile = files[i]; + Logger::Print("Loading script {}...\n", scriptFile); - if (Utils::String::EndsWith(script, ".gsc")) + sprintf_s(path, "%s/%s", "scripts", scriptFile); + + // Scr_LoadScriptInternal will add the '.gsc' suffix so we remove it + path[std::strlen(path) - 4] = '\0'; + + if (!Game::Scr_LoadScript(path)) { - script = script.substr(0, script.size() - 4); + Logger::Print("Script {} encountered an error while loading. (doesn't exist?)", path); + continue; } - Logger::Print("Loading script {}.gsc...\n", script); - - if (!Game::Scr_LoadScript(script.data())) - { - Logger::Print("Script {} encountered an error while loading. (doesn't exist?)", script); - Logger::Error(Game::ERR_DROP, "Could not find script '{}'", script); - return; - } - - Logger::Print("Script {}.gsc loaded successfully.\n", script); + Logger::Print("Script {}.gsc loaded successfully.\n", path); Logger::Debug("Finding script handle main or init..."); - const auto initHandle = Game::Scr_GetFunctionHandle(script.data(), "init"); + const auto initHandle = Game::Scr_GetFunctionHandle(path, "init"); if (initHandle != 0) { Script::ScriptInitHandles.push_back(initHandle); } - const auto mainHandle = Game::Scr_GetFunctionHandle(script.data(), "main"); + const auto mainHandle = Game::Scr_GetFunctionHandle(path, "main"); if (mainHandle != 0) { Script::ScriptMainHandles.push_back(mainHandle); @@ -271,6 +271,7 @@ namespace Components // Allow scripts with no handles } + Game::FS_FreeFileList(files, 10); Game::GScr_LoadGameTypeScript(); } @@ -397,18 +398,16 @@ namespace Components { // execute our hook pushad - call Script::StoreScriptBaseProgramNum - popad // execute overwritten code caused by the jump hook - sub eax, ds:201A460h // gScrVarPub_programBuffer - add esp, 0Ch - mov ds : 1CFEEF8h, eax // gScrCompilePub_programLen + sub eax, ds:201A460h // gScrVarPub_programBuffer + add esp, 0Ch + mov ds:1CFEEF8h, eax // gScrCompilePub_programLen // jump back to the original code - push 426C3Bh + push 426C3Bh retn } } @@ -535,6 +534,14 @@ namespace Components return &Game::svs_clients[ent->s.number]; } + void Script::ShowDeprecationWarning() + { + Toast::Show("cardicon_gumby", "WARNING!", "You are using deprecated HttpGet/HttpCancel GSC function.", 2048); + Logger::Print(Game::CON_CHANNEL_SCRIPT, "*** DEPRECATION WARNING ***\n"); + Logger::PrintError(Game::CON_CHANNEL_ERROR, "Attempted to execute deprecated built-in HttpGet/HttpCancel! These functions have been deemed unsafe and are scheduled for removal. Please update your mod!\n"); + Logger::Print(Game::CON_CHANNEL_SCRIPT, "***************************\n"); + } + void Script::AddFunctions() { Script::AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(, ) @@ -632,7 +639,7 @@ namespace Components Utils::Hook(0x61E92E, Script::VMExecuteInternalStub, HOOK_JUMP).install()->quick(); Utils::Hook::Nop(0x61E933, 1); - Scheduler::Loop([]() + Scheduler::Loop([] { if (!Game::SV_Loaded()) return; @@ -641,11 +648,12 @@ namespace Components if (Script::LastFrameTime != -1) { - const auto timeScale = Dvar::Var("timescale").get(); - const auto timeTaken = static_cast((nowMs - Script::LastFrameTime) * timeScale); + const auto timeTaken = (nowMs - Script::LastFrameTime) * static_cast((*Game::com_timescale)->current.value); if (timeTaken >= 500) + { Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "Hitch warning: {} msec frame time\n", timeTaken); + } } Script::LastFrameTime = nowMs; diff --git a/src/Components/Modules/GSC/Script.hpp b/src/Components/Modules/GSC/Script.hpp index 0b585d94..d80f952e 100644 --- a/src/Components/Modules/GSC/Script.hpp +++ b/src/Components/Modules/GSC/Script.hpp @@ -14,6 +14,8 @@ namespace Components static const char* GetCodePosForParam(int index); + static void ShowDeprecationWarning(); + private: struct ScriptFunction { @@ -59,7 +61,6 @@ namespace Components static void Scr_StartupGameType_Stub(); static void GScr_LoadGameTypeScript_Stub(); - static bool IsDeprecated(const std::string& name); static Game::BuiltinFunction BuiltIn_GetFunctionStub(const char** pName, int* type); static Game::BuiltinMethod BuiltIn_GetMethodStub(const char** pName, int* type); diff --git a/src/Components/Modules/GSC/ScriptExtension.cpp b/src/Components/Modules/GSC/ScriptExtension.cpp index fbcc8f06..e3c5cbae 100644 --- a/src/Components/Modules/GSC/ScriptExtension.cpp +++ b/src/Components/Modules/GSC/ScriptExtension.cpp @@ -175,16 +175,16 @@ namespace Components // Func present on IW5 Script::AddFunction("IsEndStr", [] // gsc: IsEndStr(, ) { - const auto* s1 = Game::Scr_GetString(0); - const auto* s2 = Game::Scr_GetString(1); + const auto* str = Game::Scr_GetString(0); + const auto* suffix = Game::Scr_GetString(1); - if (s1 == nullptr || s2 == nullptr) + if (str == nullptr || suffix == nullptr) { Game::Scr_Error("^1IsEndStr: Illegal parameters!\n"); return; } - Game::Scr_AddBool(Utils::String::EndsWith(s1, s2)); + Game::Scr_AddBool(Utils::String::EndsWith(str, suffix)); }); Script::AddFunction("IsArray", [] // gsc: IsArray() @@ -206,6 +206,41 @@ namespace Components Game::Scr_AddBool(result); }); + + // Func present on IW5 + Script::AddFunction("CastFloat", [] // gsc: CastFloat() + { + switch (Game::Scr_GetType(0)) + { + case Game::VAR_STRING: + Game::Scr_AddFloat(static_cast(std::atof(Game::Scr_GetString(0)))); + break; + case Game::VAR_FLOAT: + Game::Scr_AddFloat(Game::Scr_GetFloat(0)); + break; + case Game::VAR_INTEGER: + Game::Scr_AddFloat(static_cast(Game::Scr_GetInt(0))); + break; + default: + Game::Scr_ParamError(0, Utils::String::VA("cannot cast %s to float", Game::Scr_GetTypeName(0))); + break; + } + }); + + Script::AddFunction("Strtol", [] // gsc: Strtol(, ) + { + const auto* input = Game::Scr_GetString(0); + const auto base = Game::Scr_GetInt(1); + + char* end; + const auto result = std::strtol(input, &end, base); + if (input == end) + { + Game::Scr_ParamError(0, "cannot cast string to int"); + } + + Game::Scr_AddInt(result); + }); } void ScriptExtension::AddMethods() @@ -216,7 +251,7 @@ namespace Components const auto* ent = Game::GetPlayerEntity(entref); const auto* client = Script::GetClient(ent); - std::string ip = Game::NET_AdrToString(client->netchan.remoteAddress); + std::string ip = Game::NET_AdrToString(client->header.netchan.remoteAddress); if (const auto pos = ip.find_first_of(":"); pos != std::string::npos) ip.erase(ip.begin() + pos, ip.end()); // Erase port @@ -241,7 +276,7 @@ namespace Components const auto* ent = Game::GetPlayerEntity(entref); auto* client = Script::GetClient(ent); - client->ping = static_cast(ping); + client->ping = ping; }); } diff --git a/src/Components/Modules/GSC/ScriptStorage.cpp b/src/Components/Modules/GSC/ScriptStorage.cpp index b169d1ea..a89e8512 100644 --- a/src/Components/Modules/GSC/ScriptStorage.cpp +++ b/src/Components/Modules/GSC/ScriptStorage.cpp @@ -82,7 +82,7 @@ namespace Components return; } - const json11::Json json = Data; + const nlohmann::json json = Data; FileSystem::FileWriter("scriptdata/scriptstorage.json").write(json.dump()); }); diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index ad3ab9d0..4942ff58 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -169,8 +169,8 @@ namespace Components {Game::K_APAD_RIGHT, Game::K_RIGHTARROW}, }; - Gamepad::GamePad Gamepad::gamePads[Game::MAX_GAMEPADS]{}; - Gamepad::GamePadGlobals Gamepad::gamePadGlobals[Game::MAX_GAMEPADS]{{}}; + Gamepad::GamePad Gamepad::gamePads[Game::MAX_GPAD_COUNT]{}; + Gamepad::GamePadGlobals Gamepad::gamePadGlobals[Game::MAX_GPAD_COUNT]{{}}; int Gamepad::gamePadBindingsModifiedFlags = 0; Dvar::Var Gamepad::gpad_enabled; @@ -241,12 +241,12 @@ namespace Components mov dl, byte ptr[edi + 1Ah] // to_forwardMove mov dh, byte ptr[edi + 1Bh] // to_rightMove - mov[esp + 30h], dx // to_buttons + mov [esp + 30h], dx // to_buttons - mov dl, byte ptr[ebp + 1Ah] // from_forwardMove - mov dh, byte ptr[ebp + 1Bh] // from_rightMove + mov dl, byte ptr [ebp + 1Ah] // from_forwardMove + mov dh, byte ptr [ebp + 1Bh] // from_rightMove - mov[esp + 2Ch], dx // from_buttons + mov [esp + 2Ch], dx // from_buttons // return back push 0x60E40E @@ -261,7 +261,7 @@ namespace Components if (Game::MSG_ReadBit(msg)) { - short movementBits = static_cast(key ^ Game::MSG_ReadBits(msg, 16)); + const auto movementBits = static_cast(key ^ Game::MSG_ReadBits(msg, 16)); forward = static_cast(movementBits); right = static_cast(movementBits >> 8); @@ -314,7 +314,8 @@ namespace Components bool Gamepad::GPad_Check(const int gamePadIndex, const int portIndex) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& gamePad = gamePads[gamePadIndex]; if (XInputGetCapabilities(portIndex, XINPUT_FLAG_GAMEPAD, &gamePad.caps) == ERROR_SUCCESS) @@ -332,7 +333,7 @@ namespace Components { auto currentGamePadNum = 0; - for (auto currentPort = 0; currentPort < XUSER_MAX_COUNT && currentGamePadNum < Game::MAX_GAMEPADS; currentPort++) + for (auto currentPort = 0; currentPort < XUSER_MAX_COUNT && currentGamePadNum < Game::MAX_GPAD_COUNT; currentPort++) { if (GPad_Check(currentGamePadNum, currentPort)) currentGamePadNum++; @@ -366,7 +367,7 @@ namespace Components bool Gamepad::AimAssist_IsPlayerUsingOffhand(Game::AimAssistPlayerState* ps) { // Check offhand flag - if ((ps->weapFlags & 2) == 0) + if ((ps->weapFlags & Game::PWF_USING_OFFHAND) == 0) return false; // If offhand weapon has no id we are not using one @@ -421,7 +422,8 @@ namespace Components bool Gamepad::AimAssist_IsLockonActive(const int gamePadIndex) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& aaGlob = Game::aaGlobArray[gamePadIndex]; if (!aim_lockon_enabled.get() || !gpad_lockon_enabled.get()) @@ -439,7 +441,9 @@ namespace Components void Gamepad::AimAssist_ApplyLockOn(const Game::AimInput* input, Game::AimOutput* output) { assert(input); - assert(input->localClientNum < Game::MAX_GAMEPADS); + assert(output); + AssertIn(input->localClientNum, Game::STATIC_MAX_LOCAL_CLIENTS); + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; const auto prevTargetEnt = aaGlob.lockOnTargetEnt; @@ -554,10 +558,11 @@ namespace Components void Gamepad::AimAssist_CalcSlowdown(const Game::AimInput* input, float* pitchScale, float* yawScale) { assert(input); - assert(input->localClientNum < Game::MAX_GAMEPADS); - auto& aaGlob = Game::aaGlobArray[input->localClientNum]; assert(pitchScale); assert(yawScale); + AssertIn(input->localClientNum, Game::STATIC_MAX_LOCAL_CLIENTS); + + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; *pitchScale = 1.0f; *yawScale = 1.0f; @@ -586,7 +591,10 @@ namespace Components void Gamepad::AimAssist_ApplyTurnRates(const Game::AimInput* input, Game::AimOutput* output) { - assert(input->localClientNum < Game::MAX_GAMEPADS); + assert(input); + assert(output); + AssertIn(input->localClientNum, Game::STATIC_MAX_LOCAL_CLIENTS); + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; auto slowdownPitchScale = 0.0f; @@ -649,7 +657,8 @@ namespace Components void Gamepad::AimAssist_UpdateGamePadInput(const Game::AimInput* input, Game::AimOutput* output) { - assert(input->localClientNum < Game::MAX_GAMEPADS); + AssertIn(input->localClientNum, Game::STATIC_MAX_LOCAL_CLIENTS); + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; output->pitch = input->pitch; @@ -784,8 +793,8 @@ namespace Components float Gamepad::CL_GamepadAxisValue(const int gamePadIndex, const Game::GamepadVirtualAxis virtualAxis) { - assert(gamePadIndex < Game::MAX_GAMEPADS); assert(virtualAxis > Game::GPAD_VIRTAXIS_NONE && virtualAxis < Game::GPAD_VIRTAXIS_COUNT); + const auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; const auto& [physicalAxis, mapType] = gamePadGlobal.axes.virtualAxes[virtualAxis]; @@ -818,7 +827,8 @@ namespace Components void Gamepad::CL_GamepadMove(const int gamePadIndex, Game::usercmd_s* cmd, const float frameTimeBase) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& gamePad = gamePads[gamePadIndex]; auto& clientActive = Game::clients[gamePadIndex]; @@ -960,7 +970,8 @@ namespace Components void Gamepad::CL_GamepadResetMenuScrollTime(const int gamePadIndex, const int key, const bool down, const unsigned time) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; if (!down) @@ -979,8 +990,8 @@ namespace Components void Gamepad::CL_GamepadGenerateAPad(const int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, unsigned time) { - assert(gamePadIndex < Game::MAX_GAMEPADS); - assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + assert(physicalAxis >= 0 && physicalAxis < Game::GPAD_PHYSAXIS_COUNT); auto& gamePad = gamePads[gamePadIndex]; @@ -1014,8 +1025,8 @@ namespace Components void Gamepad::CL_GamepadEvent(const int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, const float value, const unsigned time) { - assert(gamePadIndex < Game::MAX_GAMEPADS); - assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + assert(physicalAxis >= 0 && physicalAxis < Game::GPAD_PHYSAXIS_COUNT); auto& gamePad = gamePads[gamePadIndex]; auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; @@ -1054,7 +1065,8 @@ namespace Components bool Gamepad::Scoreboard_HandleInput(int gamePadIndex, int key) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::STATIC_MAX_LOCAL_CLIENTS); + auto& keyState = Game::playerKeys[gamePadIndex]; if (keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "togglescores") == 0) @@ -1080,7 +1092,8 @@ namespace Components bool Gamepad::CL_CheckForIgnoreDueToRepeat(const int gamePadIndex, const int key, const int repeatCount, const unsigned time) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::STATIC_MAX_LOCAL_CLIENTS); + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) @@ -1113,7 +1126,7 @@ namespace Components void Gamepad::CL_GamepadButtonEvent(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); const auto pressed = buttonEvent == Game::GPAD_BUTTON_PRESSED; const auto pressedOrUpdated = pressed || buttonEvent == Game::GPAD_BUTTON_UPDATE; @@ -1199,9 +1212,9 @@ namespace Components void Gamepad::CL_GamepadButtonEventForPort(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time) { - assert(gamePadIndex < Game::MAX_GAMEPADS); - auto& gamePad = gamePads[gamePadIndex]; + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& gamePad = gamePads[gamePadIndex]; gamePad.inUse = true; gpad_in_use.setRaw(true); @@ -1244,7 +1257,9 @@ namespace Components float Gamepad::GPad_GetStick(const int gamePadIndex, const Game::GamePadStick stick) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + assert(stick & Game::GPAD_STICK_MASK); + auto& gamePad = gamePads[gamePadIndex]; return gamePad.sticks[stick]; @@ -1252,7 +1267,7 @@ namespace Components float Gamepad::GPad_GetButton(const int gamePadIndex, Game::GamePadButton button) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); auto& gamePad = gamePads[gamePadIndex]; float value = 0.0f; @@ -1276,7 +1291,9 @@ namespace Components bool Gamepad::GPad_IsButtonPressed(const int gamePadIndex, Game::GamePadButton button) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + assert(button & (Game::GPAD_DIGITAL_MASK | Game::GPAD_ANALOG_MASK)); + auto& gamePad = gamePads[gamePadIndex]; bool down = false; @@ -1310,7 +1327,8 @@ namespace Components bool Gamepad::GPad_IsButtonReleased(int gamePadIndex, Game::GamePadButton button) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& gamePad = gamePads[gamePadIndex]; bool down = false; @@ -1340,7 +1358,8 @@ namespace Components void Gamepad::GPad_UpdateSticksDown(const int gamePadIndex) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& gamePad = gamePads[gamePadIndex]; for (auto stickIndex = 0u; stickIndex < std::extent_v; stickIndex++) @@ -1371,7 +1390,7 @@ namespace Components void Gamepad::GPad_UpdateSticks(const int gamePadIndex, const XINPUT_GAMEPAD& state) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); auto& gamePad = gamePads[gamePadIndex]; @@ -1403,7 +1422,7 @@ namespace Components void Gamepad::GPad_UpdateDigitals(const int gamePadIndex, const XINPUT_GAMEPAD& state) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); auto& gamePad = gamePads[gamePadIndex]; @@ -1425,7 +1444,7 @@ namespace Components void Gamepad::GPad_UpdateAnalogs(const int gamePadIndex, const XINPUT_GAMEPAD& state) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); auto& gamePad = gamePads[gamePadIndex]; @@ -1452,7 +1471,7 @@ namespace Components { GPad_RefreshAll(); - for (auto currentGamePadIndex = 0; currentGamePadIndex < Game::MAX_GAMEPADS; currentGamePadIndex++) + for (auto currentGamePadIndex = 0; currentGamePadIndex < Game::MAX_GPAD_COUNT; currentGamePadIndex++) { const auto& gamePad = gamePads[currentGamePadIndex]; if (!gamePad.enabled) @@ -1477,7 +1496,7 @@ namespace Components const auto time = Game::Sys_Milliseconds(); bool gpadPresent = false; - for (auto gamePadIndex = 0; gamePadIndex < Game::MAX_GAMEPADS; gamePadIndex++) + for (auto gamePadIndex = 0; gamePadIndex < Game::MAX_GPAD_COUNT; gamePadIndex++) { const auto& gamePad = gamePads[gamePadIndex]; @@ -1540,7 +1559,8 @@ namespace Components void Gamepad::Gamepad_WriteBindings(const int gamePadIndex, const int handle) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; Game::FS_Printf(handle, "unbindallaxis\n"); @@ -1584,7 +1604,7 @@ namespace Components push 0x60B26E retn - endMethod: + endMethod: push 0x60B298 retn } @@ -1592,7 +1612,7 @@ namespace Components void Gamepad::Gamepad_BindAxis(const int gamePadIndex, const Game::GamepadPhysicalAxis realIndex, const Game::GamepadVirtualAxis axisIndex, const Game::GamepadMapping mapType) { - assert(gamePadIndex < Game::MAX_GAMEPADS); + AssertIn(gamePadIndex, Game::MAX_GPAD_COUNT); assert(realIndex > Game::GPAD_PHYSAXIS_NONE && realIndex < Game::GPAD_PHYSAXIS_COUNT); assert(axisIndex > Game::GPAD_VIRTAXIS_NONE && axisIndex < Game::GPAD_VIRTAXIS_COUNT); assert(mapType > Game::GPAD_MAP_NONE && mapType < Game::GPAD_MAP_COUNT); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 2e55c67d..45969762 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -43,6 +43,8 @@ namespace Components static void OnMouseMove(int x, int y, int dx, int dy); + static Dvar::Var sv_allowAimAssist; + private: static Game::ButtonToCodeMap_t buttonList[]; static Game::StickToCodeMap_t analogStickList[4]; @@ -60,8 +62,8 @@ namespace Components static Game::keyname_t combinedLocalizedKeyNamesPs3[]; static ControllerMenuKeyMapping controllerMenuKeyMappings[]; - static GamePad gamePads[Game::MAX_GAMEPADS]; - static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS]; + static GamePad gamePads[Game::MAX_GPAD_COUNT]; + static GamePadGlobals gamePadGlobals[Game::MAX_GPAD_COUNT]; static int gamePadBindingsModifiedFlags; @@ -87,7 +89,6 @@ namespace Components static Dvar::Var gpad_slowdown_enabled; static Dvar::Var input_viewSensitivity; static Dvar::Var input_invertPitch; - static Dvar::Var sv_allowAimAssist; static Dvar::Var aim_turnrate_pitch; static Dvar::Var aim_turnrate_pitch_ads; static Dvar::Var aim_turnrate_yaw; diff --git a/src/Components/Modules/Lean.cpp b/src/Components/Modules/Lean.cpp index fad47586..90050a73 100644 --- a/src/Components/Modules/Lean.cpp +++ b/src/Components/Modules/Lean.cpp @@ -2,46 +2,48 @@ namespace Components { + Dvar::Var Lean::BGLean; + Game::kbutton_t Lean::in_leanleft; Game::kbutton_t Lean::in_leanright; void Lean::IN_LeanLeft_Up() { - Game::IN_KeyUp(&Lean::in_leanleft); + Game::IN_KeyUp(&in_leanleft); } void Lean::IN_LeanLeft_Down() { - Game::IN_KeyDown(&Lean::in_leanleft); + Game::IN_KeyDown(&in_leanleft); } void Lean::IN_LeanRight_Up() { - Game::IN_KeyUp(&Lean::in_leanright); + Game::IN_KeyUp(&in_leanright); } void Lean::IN_LeanRight_Down() { - Game::IN_KeyDown(&Lean::in_leanright); + Game::IN_KeyDown(&in_leanright); } - void Lean::SetLeanFlags(Game::usercmd_s* cmds) + void Lean::SetLeanFlags(Game::usercmd_s* cmd) { - if (Lean::in_leanleft.active || Lean::in_leanleft.wasPressed) + if ((in_leanleft.active || in_leanleft.wasPressed) && BGLean.get()) { - cmds->buttons |= BUTTON_FLAG_LEANLEFT; + cmd->buttons |= Game::CMD_BUTTON_LEAN_LEFT; } - if (Lean::in_leanright.active || Lean::in_leanright.wasPressed) + if ((in_leanright.active || in_leanright.wasPressed) && BGLean.get()) { - cmds->buttons |= BUTTON_FLAG_LEANRIGHT; + cmd->buttons |= Game::CMD_BUTTON_LEAN_RIGHT; } - Lean::in_leanleft.wasPressed = false; - Lean::in_leanright.wasPressed = false; + in_leanleft.wasPressed = false; + in_leanright.wasPressed = false; } - void __declspec(naked) Lean::CL_CmdButtonsStub() + void __declspec(naked) Lean::CL_CmdButtons_Stub() { __asm { @@ -51,21 +53,35 @@ namespace Components pushad push esi - call Lean::SetLeanFlags + call SetLeanFlags pop esi popad retn } } + void Lean::PM_UpdateLean_Stub(Game::playerState_s* ps, float msec, Game::usercmd_s* cmd, void(*capsuleTrace)(Game::trace_t*, const float*, const float*, const Game::Bounds*, int, int)) + { + if (BGLean.get()) + { + Game::PM_UpdateLean(ps, msec, cmd, capsuleTrace); + } + } + Lean::Lean() { - Command::AddRaw("+leanleft", Lean::IN_LeanLeft_Down, true); - Command::AddRaw("-leanleft", Lean::IN_LeanLeft_Up, true); + Command::AddRaw("+leanleft", IN_LeanLeft_Down, true); + Command::AddRaw("-leanleft", IN_LeanLeft_Up, true); - Command::AddRaw("+leanright", Lean::IN_LeanRight_Down, true); - Command::AddRaw("-leanright", Lean::IN_LeanRight_Up, true); + Command::AddRaw("+leanright", IN_LeanRight_Down, true); + Command::AddRaw("-leanright", IN_LeanRight_Up, true); - Utils::Hook(0x5A6D84, Lean::CL_CmdButtonsStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A6D84, CL_CmdButtons_Stub, HOOK_CALL).install()->quick(); + + Utils::Hook(0x4A0C72, PM_UpdateLean_Stub, HOOK_CALL).install()->quick(); + Utils::Hook(0x4A0D72, PM_UpdateLean_Stub, HOOK_CALL).install()->quick(); + + BGLean = Dvar::Register("bg_lean", true, + Game::DVAR_CODINFO, "Enable CoD4 leaning"); } } diff --git a/src/Components/Modules/Lean.hpp b/src/Components/Modules/Lean.hpp index 4ae28d51..183aaaa0 100644 --- a/src/Components/Modules/Lean.hpp +++ b/src/Components/Modules/Lean.hpp @@ -1,8 +1,5 @@ #pragma once -#define BUTTON_FLAG_LEANLEFT 0x40 -#define BUTTON_FLAG_LEANRIGHT 0x80 - namespace Components { class Lean : public Component @@ -10,6 +7,8 @@ namespace Components public: Lean(); + static Dvar::Var BGLean; + private: static Game::kbutton_t in_leanleft; static Game::kbutton_t in_leanright; @@ -20,7 +19,9 @@ namespace Components static void IN_LeanRight_Up(); static void IN_LeanRight_Down(); - static void CL_CmdButtonsStub(); - static void SetLeanFlags(Game::usercmd_s* cmds); + static void CL_CmdButtons_Stub(); + static void SetLeanFlags(Game::usercmd_s* cmd); + + static void PM_UpdateLean_Stub(Game::playerState_s* ps, float msec, Game::usercmd_s* cmd, void(*capsuleTrace)(Game::trace_t*, const float*, const float*, const Game::Bounds*, int, int)); }; } diff --git a/src/Components/Modules/Localization.cpp b/src/Components/Modules/Localization.cpp index 8e755938..845b1aa9 100644 --- a/src/Components/Modules/Localization.cpp +++ b/src/Components/Modules/Localization.cpp @@ -249,6 +249,144 @@ namespace Components Localization::Set("IW4X_CREDITS", credits); } + const char* Localization::SEH_LocalizeTextMessageStub(const char* pszInputBuffer, const char* pszMessageType, Game::msgLocErrType_t errType) + { + constexpr auto szStringCount = 10; + constexpr auto szStringSize = 1024; + + char szInsertBuf[szStringSize]; + char szTokenBuf[szStringSize]; + + static thread_local int iCurrString; + static thread_local char szStrings[szStringCount][szStringSize]; + + iCurrString = (iCurrString + 1) % szStringCount; + std::memset(szStrings[iCurrString], 0, sizeof(szStrings[0])); + auto* pszString = szStrings[iCurrString]; + auto iLen = 0; + auto bLocOn = 1; + auto bInsertEnabled = 1; + auto iInsertLevel = 0; + auto insertIndex = 1; + auto bLocSkipped = 0; + const auto* pszTokenStart = pszInputBuffer; + const auto* pszIn = pszInputBuffer; + + auto i = 0; + while (*pszTokenStart) + { + if (*pszIn && *pszIn != '\x14' && *pszIn != '\x15' && *pszIn != '\x16') + { + ++pszIn; + continue; + } + + if (pszIn > pszTokenStart) + { + auto iTokenLen = pszIn - pszTokenStart; + Game::I_strncpyz_s(szTokenBuf, sizeof(szTokenBuf), pszTokenStart, pszIn - pszTokenStart); + if (bLocOn) + { + if (!Game::SEH_GetLocalizedTokenReference(szTokenBuf, szTokenBuf, pszMessageType, errType)) + { + return nullptr; + } + + iTokenLen = std::strlen(szTokenBuf); + } + + if (iTokenLen + iLen >= szStringSize) + { + Game::Com_Printf(Game::CON_CHANNEL_SYSTEM, "%s too long when translated\n", pszMessageType); + return nullptr; + } + + for (i = 0; i < iTokenLen - 2; ++i) + { + if (!std::strncmp(&szTokenBuf[i], "&&", 2) && std::isdigit(szTokenBuf[i + 2])) + { + if (bInsertEnabled) + { + ++iInsertLevel; + } + else + { + szTokenBuf[i] = '\x16'; + bLocSkipped = 1; + } + } + } + + if (iInsertLevel <= 0 || iLen <= 0) + { + Game::I_strcpy(&pszString[iLen], szStringSize - iLen, szTokenBuf); + } + else + { + for (i = 0; i < iLen - 2; ++i) + { + if (!std::strncmp(&pszString[i], "&&", 2) && std::isdigit(pszString[i + 2])) + { + const auto digit = pszString[i + 2] - 48; + if (!digit) + { + Game::Com_Printf(Game::CON_CHANNEL_SYSTEM, "%s cannot have &&0 as conversion format: \"%s\"\n", pszMessageType, pszInputBuffer); + } + if (digit == insertIndex) + { + Game::I_strcpy(szInsertBuf, sizeof(szInsertBuf), &pszString[i + 3]); + pszString[i] = 0; + ++insertIndex; + break; + } + } + } + + Game::I_strcpy(&pszString[i], szStringSize - i, szTokenBuf); + Game::I_strcpy(&pszString[iTokenLen + i], szStringSize - (iTokenLen + i), szInsertBuf); + + iLen -= 3; + --iInsertLevel; + } + + iLen += iTokenLen; + } + + bInsertEnabled = 1; + if (*pszIn == '\x14') + { + bLocOn = 1; + ++pszIn; + } + else if (*pszIn == '\x15') + { + bLocOn = 0; + ++pszIn; + } + + if (*pszIn == '\x16') + { + bInsertEnabled = 0; + ++pszIn; + } + + pszTokenStart = pszIn; + } + + if (bLocSkipped) + { + for (i = 0; i < iLen; ++i) + { + if (pszString[i] == '\x16') + { + pszString[i] = '%'; + } + } + } + + return pszString; + } + Localization::Localization() { Localization::SetCredits(); @@ -279,6 +417,9 @@ namespace Components // Overwrite SetString Utils::Hook(0x4CE5EE, Localization::SetStringStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x49D4A0, Localization::SEH_LocalizeTextMessageStub, HOOK_JUMP).install()->quick(); + Utils::Hook::Nop(0x49D4A5, 1); + Localization::UseLocalization = Dvar::Register("ui_localize", true, Game::DVAR_NONE, "Use localization strings"); // Generate localized entries for custom classes above 10 diff --git a/src/Components/Modules/Localization.hpp b/src/Components/Modules/Localization.hpp index dea1dd94..07397c40 100644 --- a/src/Components/Modules/Localization.hpp +++ b/src/Components/Modules/Localization.hpp @@ -24,5 +24,7 @@ namespace Components static void LoadLanguageStrings(); static void SELoadLanguageStub(); static void SetCredits(); + + static const char* SEH_LocalizeTextMessageStub(const char* pszInputBuffer, const char* pszMessageType, Game::msgLocErrType_t errType); }; } diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index a700c693..e620af4f 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -28,7 +28,7 @@ namespace Components { std::string out = msg; - // Filter out coloured strings + // Filter out coloured strings for stdout if (out[0] == '^' && out[1] != '\0') { out = out.substr(2); @@ -48,11 +48,11 @@ namespace Components if (!Game::Sys_IsMainThread()) { - Logger::EnqueueMessage(out); + Logger::EnqueueMessage(msg); } else { - Game::Com_PrintMessage(channel, out.data(), 0); + Game::Com_PrintMessage(channel, msg.data(), 0); } } @@ -284,7 +284,7 @@ namespace Components if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast(num) < Logger::LoggingAddresses[0].size()) { auto addr = Logger::LoggingAddresses[0].begin() + num; - Logger::Print("Address {} removed\n", addr->getCString()); + Logger::Print("Address {} removed\n", addr->getString()); Logger::LoggingAddresses[0].erase(addr); } else @@ -295,11 +295,11 @@ namespace Components if (i != Logger::LoggingAddresses[0].end()) { Logger::LoggingAddresses[0].erase(i); - Logger::Print("Address {} removed\n", addr.getCString()); + Logger::Print("Address {} removed\n", addr.getString()); } else { - Logger::Print("Address {} not found!\n", addr.getCString()); + Logger::Print("Address {} not found!\n", addr.getString()); } } }); @@ -311,7 +311,7 @@ namespace Components for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i) { - Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[0][i].getCString()); + Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[0][i].getString()); } }); @@ -335,7 +335,7 @@ namespace Components if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast(num) < Logger::LoggingAddresses[1].size()) { const auto addr = Logger::LoggingAddresses[1].begin() + num; - Logger::Print("Address {} removed\n", addr->getCString()); + Logger::Print("Address {} removed\n", addr->getString()); Logger::LoggingAddresses[1].erase(addr); } else @@ -346,11 +346,11 @@ namespace Components if (i != Logger::LoggingAddresses[1].end()) { Logger::LoggingAddresses[1].erase(i); - Logger::Print("Address {} removed\n", addr.getCString()); + Logger::Print("Address {} removed\n", addr.getString()); } else { - Logger::Print("Address {} not found!\n", addr.getCString()); + Logger::Print("Address {} not found!\n", addr.getString()); } } }); @@ -362,7 +362,7 @@ namespace Components for (std::size_t i = 0; i < Logger::LoggingAddresses[1].size(); ++i) { - Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[1][i].getCString()); + Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[1][i].getString()); } }); } @@ -397,9 +397,9 @@ namespace Components lock.unlock(); // Flush the console log - if (const auto logfile = *reinterpret_cast(0x1AD8F28)) + if (*Game::logfile) { - Game::FS_FCloseFile(logfile); + Game::FS_FCloseFile(*Game::logfile); } } } diff --git a/src/Components/Modules/MapRotation.cpp b/src/Components/Modules/MapRotation.cpp index 5f5210f1..2c3da9cf 100644 --- a/src/Components/Modules/MapRotation.cpp +++ b/src/Components/Modules/MapRotation.cpp @@ -5,10 +5,6 @@ namespace Components Dvar::Var MapRotation::SVRandomMapRotation; Dvar::Var MapRotation::SVDontRotate; - Game::dvar_t** MapRotation::SVMapRotation = reinterpret_cast(0x62C7C44); - Game::dvar_t** MapRotation::SVMapRotationCurrent = reinterpret_cast(0x2098DF0); - Game::dvar_t** MapRotation::SVMapname = reinterpret_cast(0x2098DDC); - MapRotation::RotationData MapRotation::DedicatedRotation; MapRotation::RotationData::RotationData() @@ -62,7 +58,16 @@ namespace Components } } - json11::Json MapRotation::RotationData::to_json() const + bool MapRotation::RotationData::contains(const std::string& key, const std::string& value) const + { + return std::ranges::any_of(this->rotationEntries_, + [&](const auto& entry) + { + return entry.first == key && entry.second == value; + }); + } + + nlohmann::json MapRotation::RotationData::to_json() const { std::vector mapVector; std::vector gametypeVector; @@ -80,7 +85,7 @@ namespace Components } - json11::Json mapRotationJson = json11::Json::object + nlohmann::json mapRotationJson = nlohmann::json { {"maps", mapVector}, {"gametypes", gametypeVector}, @@ -107,12 +112,23 @@ namespace Components } catch (const std::exception& ex) { - Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}: {} contains invalid data!\n", ex.what(), (*SVMapRotation)->name); + Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}: {} contains invalid data!\n", ex.what(), (*Game::sv_mapRotation)->name); } Logger::Debug("DedicatedRotation size after parsing is '{}'", DedicatedRotation.getEntriesSize()); } + void MapRotation::LoadMapRotation() + { + const std::string mapRotation = (*Game::sv_mapRotation)->current.string; + // People may have sv_mapRotation empty because they only use 'addMap' or 'addGametype' + if (!mapRotation.empty()) + { + Logger::Debug("sv_mapRotation is not empty. Parsing..."); + LoadRotation(mapRotation); + } + } + void MapRotation::AddMapRotationCommands() { Command::Add("addMap", [](Command::Params* params) @@ -138,6 +154,11 @@ namespace Components }); } + bool MapRotation::Contains(const std::string& key, const std::string& value) + { + return DedicatedRotation.contains(key, value); + } + bool MapRotation::ShouldRotate() { if (!Dedicated::IsEnabled() && SVDontRotate.get()) @@ -160,13 +181,13 @@ namespace Components { assert(!map.empty()); - if (Dvar::Var("sv_cheats").get()) + if ((*Game::sv_cheats)->current.enabled) { - Command::Execute(Utils::String::VA("devmap %s", map.data()), true); + Command::Execute(std::format("devmap {}", map), true); } else { - Command::Execute(Utils::String::VA("map %s", map.data()), true); + Command::Execute(std::format("map {}", map), true); } } @@ -178,7 +199,7 @@ namespace Components void MapRotation::RestartCurrentMap() { - std::string svMapname = (*SVMapname)->current.string; + std::string svMapname = (*Game::sv_mapname)->current.string; if (svMapname.empty()) { @@ -224,24 +245,24 @@ namespace Components assert(!data.empty()); // Ook, ook, eek - Logger::Warning(Game::CON_CHANNEL_SERVER, "You are using deprecated {}", (*SVMapRotationCurrent)->name); + Logger::Warning(Game::CON_CHANNEL_SERVER, "You are using deprecated {}", (*Game::sv_mapRotationCurrent)->name); RotationData rotationCurrent; try { - Logger::Debug("Parsing {}", (*SVMapRotationCurrent)->name); + Logger::Debug("Parsing {}", (*Game::sv_mapRotationCurrent)->name); rotationCurrent.parse(data); } catch (const std::exception& ex) { - Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}: {} contains invalid data!\n", ex.what(), (*SVMapRotationCurrent)->name); + Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}: {} contains invalid data!\n", ex.what(), (*Game::sv_mapRotationCurrent)->name); } - Game::Dvar_SetString(*SVMapRotationCurrent, ""); + Game::Dvar_SetString(*Game::sv_mapRotationCurrent, ""); if (rotationCurrent.getEntriesSize() == 0) { - Logger::Print(Game::CON_CHANNEL_SERVER, "{} is empty or contains invalid data. Restarting map\n", (*SVMapRotationCurrent)->name); + Logger::Print(Game::CON_CHANNEL_SERVER, "{} is empty or contains invalid data. Restarting map\n", (*Game::sv_mapRotationCurrent)->name); RestartCurrentMap(); return; } @@ -272,25 +293,18 @@ namespace Components Logger::Print(Game::CON_CHANNEL_SERVER, "Rotating map...\n"); // This takes priority because of backwards compatibility - const std::string mapRotationCurrent = (*SVMapRotationCurrent)->current.string; + const std::string mapRotationCurrent = (*Game::sv_mapRotationCurrent)->current.string; if (!mapRotationCurrent.empty()) { - Logger::Debug("Applying {}", (*SVMapRotationCurrent)->name); + Logger::Debug("Applying {}", (*Game::sv_mapRotationCurrent)->name); ApplyMapRotationCurrent(mapRotationCurrent); return; } - const std::string mapRotation = (*SVMapRotation)->current.string; - // People may have sv_mapRotation empty because they only use 'addMap' or 'addGametype' - if (!mapRotation.empty()) - { - Logger::Debug("sv_mapRotation is not empty. Parsing..."); - LoadRotation(mapRotation); - } - + LoadMapRotation(); if (DedicatedRotation.getEntriesSize() == 0) { - Logger::Print(Game::CON_CHANNEL_SERVER, "{} is empty or contains invalid data. Restarting map\n", (*SVMapRotation)->name); + Logger::Print(Game::CON_CHANNEL_SERVER, "{} is empty or contains invalid data. Restarting map\n", (*Game::sv_mapRotation)->name); RestartCurrentMap(); return; } diff --git a/src/Components/Modules/MapRotation.hpp b/src/Components/Modules/MapRotation.hpp index 3c4a0efe..4a57d1a0 100644 --- a/src/Components/Modules/MapRotation.hpp +++ b/src/Components/Modules/MapRotation.hpp @@ -7,6 +7,8 @@ namespace Components public: MapRotation(); + static bool Contains(const std::string& key, const std::string& value); + bool unitTest() override; private: @@ -33,8 +35,9 @@ namespace Components void parse(const std::string& data); - // Json11 Implicit constructor - [[nodiscard]] json11::Json to_json() const; + [[nodiscard]] bool contains(const std::string& key, const std::string& value) const; + + [[nodiscard]] nlohmann::json to_json() const; private: std::vector rotationEntries_; @@ -45,15 +48,12 @@ namespace Components // Rotation Dvars static Dvar::Var SVRandomMapRotation; static Dvar::Var SVDontRotate; - // Game Dvars - static Game::dvar_t** SVMapRotation; - static Game::dvar_t** SVMapRotationCurrent; - static Game::dvar_t** SVMapname; // Holds the parsed data from sv_mapRotation static RotationData DedicatedRotation; static void LoadRotation(const std::string& data); + static void LoadMapRotation(); // Use these commands before SV_MapRotate_f is called static void AddMapRotationCommands(); diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 39ef37c3..13059ad0 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -96,12 +96,12 @@ namespace Components const char* Maps::LoadArenaFileStub(const char* name, char* buffer, int size) { - std::string data = Game::Scr_AddSourceBuffer(nullptr, name, nullptr, false); + std::string data = RawFiles::ReadRawFile(name, buffer, size); - if(Maps::UserMap.isValid()) + if (Maps::UserMap.isValid()) { - std::string mapname = Maps::UserMap.getName(); - std::string arena = Utils::String::VA("usermaps/%s/%s.arena", mapname.data(), mapname.data()); + const std::string mapname = Maps::UserMap.getName(); + const auto* arena = Utils::String::VA("usermaps/%s/%s.arena", mapname.data(), mapname.data()); if (Utils::IO::FileExists(arena)) { @@ -109,7 +109,7 @@ namespace Components } } - strncpy_s(buffer, size, data.data(), data.size()); + strncpy_s(buffer, size, data.data(), _TRUNCATE); return buffer; } @@ -768,7 +768,7 @@ namespace Components Maps::UpdateDlcStatus(); - UIScript::Add("downloadDLC", [](UIScript::Token token) + UIScript::Add("downloadDLC", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { int dlc = token.get(); diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 32221eeb..ed403a63 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -785,80 +785,85 @@ namespace Components } }, HOOK_CALL).install()->quick(); - // Intercept menu painting - Utils::Hook(0x4FFBDF, Menus::IsMenuVisible, HOOK_CALL).install()->quick(); + // Intercept menu painting + Utils::Hook(0x4FFBDF, Menus::IsMenuVisible, HOOK_CALL).install()->quick(); - // disable the 2 new tokens in ItemParse_rect - Utils::Hook::Set(0x640693, 0xEB); + // disable the 2 new tokens in ItemParse_rect + Utils::Hook::Set(0x640693, 0xEB); - // don't load ASSET_TYPE_MENU assets for every menu (might cause patch menus to fail) - Utils::Hook::Nop(0x453406, 5); + // don't load ASSET_TYPE_MENU assets for every menu (might cause patch menus to fail) + Utils::Hook::Nop(0x453406, 5); - //make Com_Error and similar go back to main_text instead of menu_xboxlive. - Utils::Hook::SetString(0x6FC790, "main_text"); + // 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", [](Command::Params* params) + { + if (params->size() != 2) { - if (params->size() != 2) - { - Logger::Print("USAGE: openmenu \n"); - return; - } + Logger::Print("USAGE: openmenu \n"); + return; + } - // Not quite sure if we want to do this if we're not ingame, but it's only needed for ingame menus. - if (Dvar::Var("cl_ingame").get()) - { - Game::Key_SetCatcher(0, 16); - } - - Game::Menus_OpenByName(Game::uiContext, params->get(1)); - }); - - Command::Add("reloadmenus", [](Command::Params*) + // Not quite sure if we want to do this if we're not ingame, but it's only needed for ingame menus. + if ((*Game::cl_ingame)->current.enabled) { - // Close all menus - Game::Menus_CloseAll(Game::uiContext); + Game::Key_SetCatcher(0, 16); + } - // Free custom menus - Menus::FreeEverything(); + Game::Menus_OpenByName(Game::uiContext, params->get(1)); + }); - // Only disconnect if in-game, context is updated automatically! - if (Game::CL_IsCgameInitialized()) - { - Game::Cbuf_AddText(0, "disconnect\n"); - } - else - { - // Reinitialize ui context - Utils::Hook::Call(0x401700)(); + Command::Add("reloadmenus", [](Command::Params*) + { + // Close all menus + Game::Menus_CloseAll(Game::uiContext); - // Reopen main menu - Game::Menus_OpenByName(Game::uiContext, "main_text"); - } - }); + // Free custom menus + Menus::FreeEverything(); - Command::Add("mp_QuickMessage", [](Command::Params*) + // Only disconnect if in-game, context is updated automatically! + if (Game::CL_IsCgameInitialized()) { - Command::Execute("openmenu quickmessage"); - }); + Game::Cbuf_AddText(0, "disconnect\n"); + } + else + { + // Reinitialize ui context + Utils::Hook::Call(0x401700)(); - // Define custom menus here - Menus::Add("ui_mp/changelog.menu"); - Menus::Add("ui_mp/theater_menu.menu"); - Menus::Add("ui_mp/pc_options_multi.menu"); - Menus::Add("ui_mp/pc_options_game.menu"); - Menus::Add("ui_mp/pc_options_gamepad.menu"); - Menus::Add("ui_mp/stats_reset.menu"); - Menus::Add("ui_mp/stats_unlock.menu"); - Menus::Add("ui_mp/security_increase_popmenu.menu"); - Menus::Add("ui_mp/mod_download_popmenu.menu"); - Menus::Add("ui_mp/popup_friends.menu"); - Menus::Add("ui_mp/menu_first_launch.menu"); - Menus::Add("ui_mp/startup_messages.menu"); - Menus::Add("ui_mp/iw4x_credits.menu"); - Menus::Add("ui_mp/resetclass.menu"); - Menus::Add("ui_mp/popup_customtitle.menu"); - Menus::Add("ui_mp/popup_customclan.menu"); + // Reopen main menu + Game::Menus_OpenByName(Game::uiContext, "main_text"); + } + }); + + Command::Add("mp_QuickMessage", [](Command::Params*) + { + Command::Execute("openmenu quickmessage"); + }); + + // Define custom menus here + Menus::Add("ui_mp/changelog.menu"); + Menus::Add("ui_mp/theater_menu.menu"); + Menus::Add("ui_mp/pc_options_multi.menu"); + Menus::Add("ui_mp/pc_options_game.menu"); + Menus::Add("ui_mp/pc_options_gamepad.menu"); + Menus::Add("ui_mp/stats_reset.menu"); + Menus::Add("ui_mp/stats_unlock.menu"); + Menus::Add("ui_mp/security_increase_popmenu.menu"); + Menus::Add("ui_mp/mod_download_popmenu.menu"); + Menus::Add("ui_mp/popup_friends.menu"); + Menus::Add("ui_mp/menu_first_launch.menu"); + Menus::Add("ui_mp/startup_messages.menu"); + Menus::Add("ui_mp/iw4x_credits.menu"); + Menus::Add("ui_mp/resetclass.menu"); + Menus::Add("ui_mp/popup_customtitle.menu"); + Menus::Add("ui_mp/popup_customclan.menu"); + + Menus::Add("ui_mp/scriptmenus/callvote.menu"); + Menus::Add("ui_mp/scriptmenus/changegametype.menu"); + Menus::Add("ui_mp/scriptmenus/changemap.menu"); + Menus::Add("ui_mp/scriptmenus/kickplayer.menu"); } Menus::~Menus() diff --git a/src/Components/Modules/ModList.cpp b/src/Components/Modules/ModList.cpp index 6d4db41b..5dc9d38c 100644 --- a/src/Components/Modules/ModList.cpp +++ b/src/Components/Modules/ModList.cpp @@ -40,7 +40,7 @@ namespace Components ModList::CurrentMod = index; } - void ModList::UIScript_LoadMods(UIScript::Token) + void ModList::UIScript_LoadMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { auto folder = Dvar::Var("fs_basepath").get() + "\\mods"; Logger::Debug("Searching for mods in {}...", folder); @@ -48,7 +48,7 @@ namespace Components Logger::Debug("Found {} mods!", ModList::Mods.size()); } - void ModList::UIScript_RunMod(UIScript::Token) + void ModList::UIScript_RunMod([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (ModList::CurrentMod < ModList::Mods.size()) { @@ -56,7 +56,7 @@ namespace Components } } - void ModList::UIScript_ClearMods(UIScript::Token) + void ModList::UIScript_ClearMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { auto fsGame = Dvar::Var("fs_game"); fsGame.set(""); diff --git a/src/Components/Modules/ModList.hpp b/src/Components/Modules/ModList.hpp index 185aaed1..6dc2bb4d 100644 --- a/src/Components/Modules/ModList.hpp +++ b/src/Components/Modules/ModList.hpp @@ -18,8 +18,8 @@ namespace Components static unsigned int GetItemCount(); static const char* GetItemText(unsigned int index, int column); static void Select(unsigned int index); - static void UIScript_LoadMods(UIScript::Token); - static void UIScript_RunMod(UIScript::Token); - static void UIScript_ClearMods(UIScript::Token); + static void UIScript_LoadMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); + static void UIScript_RunMod([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); + static void UIScript_ClearMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); }; } diff --git a/src/Components/Modules/Movement.cpp b/src/Components/Modules/Movement.cpp index fe782c4b..6197387f 100644 --- a/src/Components/Modules/Movement.cpp +++ b/src/Components/Modules/Movement.cpp @@ -7,6 +7,7 @@ namespace Components Dvar::Var Movement::CGNoclipScaler; Dvar::Var Movement::BGBouncesAllAngles; Dvar::Var Movement::BGRocketJump; + Dvar::Var Movement::BGRocketJumpScale; Dvar::Var Movement::BGPlayerEjection; Dvar::Var Movement::BGPlayerCollision; Game::dvar_t* Movement::BGBounces; @@ -172,15 +173,17 @@ namespace Components } Game::gentity_s* Movement::Weapon_RocketLauncher_Fire_Hk(Game::gentity_s* ent, unsigned int weaponIndex, - float spread, Game::weaponParms* wp, const float* gunVel, Game::lockonFireParms* lockParms, bool a7) + float spread, Game::weaponParms* wp, const float* gunVel, Game::lockonFireParms* lockParms, bool magicBullet) { - auto* result = Game::Weapon_RocketLauncher_Fire(ent, weaponIndex, spread, wp, gunVel, lockParms, a7); + auto* result = Game::Weapon_RocketLauncher_Fire(ent, weaponIndex, spread, wp, gunVel, lockParms, magicBullet); - if (ent->client != nullptr && BGRocketJump.get()) + if (ent->client != nullptr && BGRocketJump.get() && + wp->weapDef->inventoryType != Game::WEAPINVENTORY_EXCLUSIVE) { - ent->client->ps.velocity[0] += (0.0f - wp->forward[0]) * 64.0f; - ent->client->ps.velocity[1] += (0.0f - wp->forward[1]) * 64.0f; - ent->client->ps.velocity[2] += (0.0f - wp->forward[2]) * 64.0f; + const auto scale = Movement::BGRocketJumpScale.get(); + ent->client->ps.velocity[0] += (0.0f - wp->forward[0]) * scale; + ent->client->ps.velocity[1] += (0.0f - wp->forward[1]) * scale; + ent->client->ps.velocity[2] += (0.0f - wp->forward[2]) * scale; } return result; @@ -217,6 +220,42 @@ namespace Components return Movement::PlayerSpectateSpeedScale.get(); } + void Movement::RegisterMovementDvars() + { + Movement::PlayerDuckedSpeedScale = Game::Dvar_RegisterFloat("player_duckedSpeedScale", + 0.65f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + "The scale applied to the player speed when ducking"); + + Movement::PlayerProneSpeedScale = Game::Dvar_RegisterFloat("player_proneSpeedScale", + 0.15f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + "The scale applied to the player speed when crawling"); + + // 3arc naming convention + Movement::CGUfoScaler = Dvar::Register("cg_ufo_scaler", + 6.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + "The speed at which ufo camera moves"); + + Movement::CGNoclipScaler = Dvar::Register("cg_noclip_scaler", + 3.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, + "The speed at which noclip camera moves"); + + Movement::BGBouncesAllAngles = Dvar::Register("bg_bouncesAllAngles", + false, Game::DVAR_CODINFO, "Force bounce from all angles"); + + Movement::BGRocketJump = Dvar::Register("bg_rocketJump", + false, Game::DVAR_CODINFO, "Enable CoD4 rocket jumps"); + + Movement::BGRocketJumpScale = Dvar::Register("bg_rocketJumpScale", + 64.0f, 1.0f, std::numeric_limits::max(), Game::DVAR_CODINFO, + "The scale applied to the pushback force of a rocket"); + + Movement::BGPlayerEjection = Dvar::Register("bg_playerEjection", + true, Game::DVAR_CODINFO, "Push intersecting players away from each other"); + + Movement::BGPlayerCollision = Dvar::Register("bg_playerCollision", + true, Game::DVAR_CODINFO, "Push intersecting players away from each other"); + } + Movement::Movement() { Scheduler::Once([] @@ -229,37 +268,8 @@ namespace Components nullptr }; - Movement::PlayerDuckedSpeedScale = Game::Dvar_RegisterFloat("player_duckedSpeedScale", - 0.65f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, - "The scale applied to the player speed when ducking"); - - Movement::PlayerProneSpeedScale = Game::Dvar_RegisterFloat("player_proneSpeedScale", - 0.15f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, - "The scale applied to the player speed when crawling"); - - // 3arc naming convention - Movement::CGUfoScaler = Dvar::Register("cg_ufo_scaler", - 6.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, - "The speed at which ufo camera moves"); - - Movement::CGNoclipScaler = Dvar::Register("cg_noclip_scaler", - 3.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO, - "The speed at which noclip camera moves"); - Movement::BGBounces = Game::Dvar_RegisterEnum("bg_bounces", bg_bouncesValues, Movement::DISABLED, Game::DVAR_CODINFO, "Bounce glitch settings"); - - Movement::BGBouncesAllAngles = Dvar::Register("bg_bouncesAllAngles", - false, Game::DVAR_CODINFO, "Force bounce from all angles"); - - Movement::BGRocketJump = Dvar::Register("bg_rocketJump", - false, Game::DVAR_CODINFO, "Enable CoD4 rocket jumps"); - - Movement::BGPlayerEjection = Dvar::Register("bg_playerEjection", - true, Game::DVAR_CODINFO, "Push intersecting players away from each other"); - - Movement::BGPlayerCollision = Dvar::Register("bg_playerCollision", - true, Game::DVAR_CODINFO, "Push intersecting players away from each other"); }, Scheduler::Pipeline::MAIN); // Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used. @@ -286,5 +296,7 @@ namespace Components Utils::Hook(0x5D8153, Movement::StuckInClient_Hk, HOOK_CALL).install()->quick(); Utils::Hook(0x45A5BF, Movement::CM_TransformedCapsuleTrace_Hk, HOOK_CALL).install()->quick(); // SV_ClipMoveToEntity Utils::Hook(0x5A0CAD, Movement::CM_TransformedCapsuleTrace_Hk, HOOK_CALL).install()->quick(); // CG_ClipMoveToEntity + + Movement::RegisterMovementDvars(); } } diff --git a/src/Components/Modules/Movement.hpp b/src/Components/Modules/Movement.hpp index 72aa3347..ddcd7bf2 100644 --- a/src/Components/Modules/Movement.hpp +++ b/src/Components/Modules/Movement.hpp @@ -15,6 +15,7 @@ namespace Components static Dvar::Var CGNoclipScaler; static Dvar::Var BGBouncesAllAngles; static Dvar::Var BGRocketJump; + static Dvar::Var BGRocketJumpScale; static Dvar::Var BGPlayerEjection; static Dvar::Var BGPlayerCollision; // Can't use Var class inside assembly stubs @@ -40,5 +41,7 @@ namespace Components static void CM_TransformedCapsuleTrace_Hk(Game::trace_t* results, const float* start, const float* end, const Game::Bounds* bounds, const Game::Bounds* capsule, int contents, const float* origin, const float* angles); static Game::dvar_t* Dvar_RegisterSpectateSpeedScale(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description); + + static void RegisterMovementDvars(); }; } diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index f434dc19..06f08b12 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -2,10 +2,10 @@ namespace Components { - std::string Network::SelectedPacket; Utils::Signal Network::StartupSignal; // Packet interception - std::unordered_map Network::Callbacks; + std::unordered_map Network::CL_Callbacks; + std::unordered_map Network::SV_Callbacks; Network::Address::Address(const std::string& addrString) { @@ -27,7 +27,7 @@ namespace Components this->address.port = htons(port); } - unsigned short Network::Address::getPort() + unsigned short Network::Address::getPort() const { return ntohs(this->address.port); } @@ -42,7 +42,7 @@ namespace Components this->address.ip = ip; } - Game::netIP_t Network::Address::getIP() + Game::netIP_t Network::Address::getIP() const { return this->address.ip; } @@ -52,7 +52,7 @@ namespace Components this->address.type = type; } - Game::netadrtype_t Network::Address::getType() + Game::netadrtype_t Network::Address::getType() const { return this->address.type; } @@ -89,7 +89,7 @@ namespace Components std::string Network::Address::getString() const { - return this->getCString(); + return {this->getCString()}; } bool Network::Address::isLocal() @@ -116,7 +116,7 @@ namespace Components bool Network::Address::isSelf() { if (Game::NET_IsLocalAddress(this->address)) return true; // Loopback - if (this->getPort() != Network::GetPort()) return false; // Port not equal + if (this->getPort() != GetPort()) return false; // Port not equal for (int i = 0; i < *Game::numIP; ++i) { @@ -129,7 +129,7 @@ namespace Components return false; } - bool Network::Address::isLoopback() + bool Network::Address::isLoopback() const { if (this->getIP().full == 0x100007f) // 127.0.0.1 { @@ -139,17 +139,17 @@ namespace Components return Game::NET_IsLocalAddress(this->address); } - bool Network::Address::isValid() + bool Network::Address::isValid() const { - return (this->getType() != Game::netadrtype_t::NA_BAD && this->getType() >= Game::netadrtype_t::NA_BOT && this->getType() <= Game::netadrtype_t::NA_IP); + return (this->getType() != Game::NA_BAD && this->getType() >= Game::NA_BOT && this->getType() <= Game::NA_IP); } - void Network::OnStart(Utils::Slot callback) + void Network::OnStart(const Utils::Slot& callback) { - Network::StartupSignal.connect(callback); + StartupSignal.connect(callback); } - void Network::Send(Game::netsrc_t type, Network::Address target, const std::string& data) + void Network::Send(Game::netsrc_t type, Address target, const std::string& data) { // NET_OutOfBandPrint only supports non-binary data! //Game::NET_OutOfBandPrint(type, *target.Get(), data.data()); @@ -159,15 +159,15 @@ namespace Components rawData.append(data); //rawData.append("\0", 1); - Network::SendRaw(type, target, rawData); + SendRaw(type, target, rawData); } - void Network::Send(Network::Address target, const std::string& data) + void Network::Send(Address target, const std::string& data) { - Network::Send(Game::netsrc_t::NS_CLIENT1, target, data); + Send(Game::netsrc_t::NS_CLIENT1, target, data); } - void Network::SendRaw(Game::netsrc_t type, Network::Address target, const std::string& data) + void Network::SendRaw(Game::netsrc_t type, Address target, const std::string& data) { if (!target.isValid()) return; @@ -176,12 +176,12 @@ namespace Components Game::Sys_SendPacket(type, data.size(), data.data(), *target.get()); } - void Network::SendRaw(Network::Address target, const std::string& data) + void Network::SendRaw(Address target, const std::string& data) { - Network::SendRaw(Game::netsrc_t::NS_CLIENT1, target, data); + SendRaw(Game::NS_CLIENT1, target, data); } - void Network::SendCommand(Game::netsrc_t type, Network::Address target, const std::string& command, const std::string& data) + void Network::SendCommand(Game::netsrc_t type, Address target, const std::string& command, const std::string& data) { // Use space as separator (possible separators are '\n', ' '). // Though, our handler only needs exactly 1 char as separator and doesn't care which char it is. @@ -191,12 +191,12 @@ namespace Components packet.append("\n", 1); packet.append(data); - Network::Send(type, target, packet); + Send(type, target, packet); } - void Network::SendCommand(Network::Address target, const std::string& command, const std::string& data) + void Network::SendCommand(Address target, const std::string& command, const std::string& data) { - Network::SendCommand(Game::netsrc_t::NS_CLIENT1, target, command, data); + SendCommand(Game::NS_CLIENT1, target, command, data); } void Network::Broadcast(unsigned short port, const std::string& data) @@ -207,25 +207,26 @@ namespace Components target.setIP(INADDR_BROADCAST); target.setType(Game::netadrtype_t::NA_BROADCAST); - Network::Send(Game::netsrc_t::NS_CLIENT1, target, data); + Send(Game::netsrc_t::NS_CLIENT1, target, data); } void Network::BroadcastRange(unsigned int min, unsigned int max, const std::string& data) { for (unsigned int i = min; i < max; ++i) { - Network::Broadcast(static_cast(i & 0xFFFF), data); + Broadcast(static_cast(i & 0xFFFF), data); } } void Network::BroadcastAll(const std::string& data) { - Network::BroadcastRange(100, 65536, data); + BroadcastRange(100, 65536, data); } void Network::NetworkStart() { - Network::StartupSignal(); + StartupSignal(); + StartupSignal.clear(); } unsigned short Network::GetPort() @@ -239,7 +240,7 @@ namespace Components { mov eax, 64D900h call eax - jmp Network::NetworkStart + jmp NetworkStart } } @@ -267,32 +268,55 @@ namespace Components if (client->reliableAcknowledge < 0) { Logger::Print(Game::conChannel_t::CON_CHANNEL_NETWORK, "Negative reliableAcknowledge from {} - cl->reliableSequence is {}, reliableAcknowledge is {}\n", - client->name, client->reliableSequence, client->reliableAcknowledge); + client->name, client->reliableSequence, client->reliableAcknowledge); client->reliableAcknowledge = client->reliableSequence; - Network::SendCommand(Game::NS_SERVER, client->netchan.remoteAddress, "error", "EXE_LOSTRELIABLECOMMANDS"); + SendCommand(Game::NS_SERVER, client->header.netchan.remoteAddress, "error", "EXE_LOSTRELIABLECOMMANDS"); return; } Utils::Hook::Call(0x414D40)(client, msg); } - void Network::OnPacket(const std::string& command, const NetworkCallback& callback) + void Network::OnClientPacket(const std::string& command, const NetworkCallback& callback) { - Network::Callbacks[Utils::String::ToLower(command)] = callback; + CL_Callbacks[Utils::String::ToLower(command)] = callback; } - bool Network::HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message) + void Network::OnServerPacket(const std::string& command, const NetworkCallback& callback) + { + SV_Callbacks[Utils::String::ToLower(command)] = callback; + } + + bool Network::CL_HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message) { const auto command_ = Utils::String::ToLower(command); - const auto handler = Network::Callbacks.find(command_); + const auto handler = CL_Callbacks.find(command_); const auto offset = command_.size() + 5; - if (static_cast(message->cursize) < offset || handler == Network::Callbacks.end()) + if (static_cast(message->cursize) < offset || handler == CL_Callbacks.end()) { return false; } - const std::string data(message->data + offset, message->cursize - offset); + const std::string data(reinterpret_cast(message->data) + offset, message->cursize - offset); + + Address address_ = address; + handler->second(address_, data); + return true; + } + + bool Network::SV_HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message) + { + const auto command_ = Utils::String::ToLower(command); + const auto handler = SV_Callbacks.find(command_); + + const auto offset = command_.size() + 5; + if (static_cast(message->cursize) < offset || handler == SV_Callbacks.end()) + { + return false; + } + + const std::string data(reinterpret_cast(message->data) + offset, message->cursize - offset); Address address_ = address; handler->second(address_, data); @@ -308,9 +332,9 @@ namespace Components pushad push ebp // msg_t - push edi // Command name + push edi // command name push eax // netadr_t pointer - call Network::HandleCommand + call CL_HandleCommand add esp, 0xC test al, al @@ -330,6 +354,37 @@ namespace Components } } + __declspec(naked) void Network::SV_HandleCommandStub() + { + __asm + { + lea eax, [esp + 0x408] + + pushad + + push esi // msg + push edi // command name + push eax // netadr_t pointer + call SV_HandleCommand + add esp, 0xC + + test al, al + + popad + + jz unhandled + + // Exit SV_ConnectionlessPacket + push 0x6267EB + retn + + unhandled: + // Proceed + push 0x6266E0 + retn + } + } + Network::Network() { AssertSize(Game::netadr_t, 20); @@ -355,25 +410,28 @@ namespace Components Utils::Hook::Set(0x4698E3, "%u.%u.%u.%u:%hu"); // Install startup handler - Utils::Hook(0x4FD4D4, Network::NetworkStartStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x4FD4D4, NetworkStartStub, HOOK_JUMP).install()->quick(); // Prevent recvfrom error spam - Utils::Hook(0x46531A, Network::PacketErrorCheck, HOOK_JUMP).install()->quick(); + Utils::Hook(0x46531A, PacketErrorCheck, HOOK_JUMP).install()->quick(); // Fix server freezer exploit - Utils::Hook(0x626996, Network::SV_ExecuteClientMessageStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x626996, SV_ExecuteClientMessageStub, HOOK_CALL).install()->quick(); // Handle client packets - Utils::Hook(0x5AA703, Network::CL_HandleCommandStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x5AA703, CL_HandleCommandStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x6266CA, SV_HandleCommandStub, HOOK_JUMP).install()->quick(); // Disable unused OOB packets handlers just to be sure Utils::Hook::Set(0x5AA5B6, 0xEB); // CL_SteamServerAuth Utils::Hook::Set(0x5AA69F, 0xEB); // echo Utils::Hook::Set(0x5AAA82, 0xEB); // SP + Utils::Hook::Set(0x5A9F18, 0xEB); // CL_VoiceConnectionTestPacket + Utils::Hook::Set(0x5A9FF3, 0xEB); // CL_HandleRelayPacket - Network::OnPacket("resolveAddress", [](const Address& address, [[maybe_unused]] const std::string& data) + OnClientPacket("resolveAddress", [](const Address& address, [[maybe_unused]] const std::string& data) { - Network::SendRaw(address, address.getString()); + SendRaw(address, address.getString()); }); } } diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index f7e84378..b3bea7e1 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -21,26 +21,26 @@ namespace Components bool operator==(const Address &obj) const; void setPort(unsigned short port); - unsigned short getPort(); + [[nodiscard]] unsigned short getPort() const; void setIP(DWORD ip); void setIP(Game::netIP_t ip); - Game::netIP_t getIP(); + [[nodiscard]] Game::netIP_t getIP() const; void setType(Game::netadrtype_t type); - Game::netadrtype_t getType(); + [[nodiscard]] Game::netadrtype_t getType() const; - sockaddr getSockAddr(); + [[nodiscard]] sockaddr getSockAddr(); void toSockAddr(sockaddr* addr); void toSockAddr(sockaddr_in* addr); Game::netadr_t* get(); - const char* getCString() const; - std::string getString() const; + [[nodiscard]] const char* getCString() const; + [[nodiscard]] std::string getString() const; - bool isLocal(); - bool isSelf(); - bool isValid(); - bool isLoopback(); + [[nodiscard]] bool isLocal(); + [[nodiscard]] bool isSelf(); + [[nodiscard]] bool isValid() const; + [[nodiscard]] bool isLoopback() const; private: Game::netadr_t address; @@ -54,7 +54,7 @@ namespace Components static unsigned short GetPort(); - static void OnStart(Utils::Slot callback); + static void OnStart(const Utils::Slot& callback); // Send quake-styled binary data static void Send(Address target, const std::string& data); @@ -72,12 +72,13 @@ namespace Components static void BroadcastRange(unsigned int min, unsigned int max, const std::string& data); static void BroadcastAll(const std::string& data); - static void OnPacket(const std::string& command, const NetworkCallback& callback); + static void OnClientPacket(const std::string& command, const NetworkCallback& callback); + static void OnServerPacket(const std::string& command, const NetworkCallback& callback); private: - static std::string SelectedPacket; static Utils::Signal StartupSignal; - static std::unordered_map Callbacks; + static std::unordered_map CL_Callbacks; + static std::unordered_map SV_Callbacks; static void NetworkStart(); static void NetworkStartStub(); @@ -86,17 +87,19 @@ namespace Components static void SV_ExecuteClientMessageStub(Game::client_t* client, Game::msg_t* msg); - static bool HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message); + static bool CL_HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message); + static bool SV_HandleCommand(Game::netadr_t* address, const char* command, const Game::msg_t* message); static void CL_HandleCommandStub(); + static void SV_HandleCommandStub(); }; } template <> struct std::hash { - std::size_t operator()(const Components::Network::Address& k) const + std::size_t operator()(const Components::Network::Address& k) const noexcept { - return (std::hash()(k.getString())); + return std::hash()(k.getString()); } }; diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index 8a75adf8..6816d8e2 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -43,7 +43,7 @@ namespace Components Dvar::Register("cl_updateoldversion", REVISION, REVISION, REVISION, Game::DVAR_INIT, "Current version number."); - UIScript::Add("checkFirstLaunch", [](UIScript::Token) + UIScript::Add("checkFirstLaunch", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (Dvar::Var("g_firstLaunch").get()) { @@ -52,7 +52,7 @@ namespace Components } }); - UIScript::Add("visitWebsite", [](UIScript::Token) + UIScript::Add("visitWebsite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { Utils::OpenUrl(Utils::Cache::GetStaticUrl("")); }); diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 0b2918bc..06a3d048 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -41,7 +41,7 @@ namespace Components Session::Send(this->address, "nodeListRequest"); Node::SendList(this->address); - Logger::Debug("Sent request to {}", this->address.getCString()); + Logger::Debug("Sent request to {}", this->address.getString()); } void Node::Entry::reset() @@ -50,7 +50,7 @@ namespace Components this->lastRequest.reset(); } - json11::Json Node::Entry::to_json() const + nlohmann::json Node::Entry::to_json() const { return this->address.getString(); } @@ -235,7 +235,7 @@ namespace Components Proto::Node::List list; if (!list.ParseFromString(data)) return; - Logger::Debug("Received response from {}", address.getCString()); + Logger::Debug("Received response from {}", address.getString()); std::lock_guard _(Node::Mutex); @@ -253,12 +253,12 @@ namespace Components { if (!Dedicated::IsEnabled() && ServerList::IsOnlineList() && !ServerList::useMasterServer && list.protocol() == PROTOCOL) { - Logger::Debug("Inserting {} into the serverlist", address.getCString()); + Logger::Debug("Inserting {} into the serverlist", address.getString()); ServerList::InsertRequest(address); } else { - Logger::Debug("Dropping serverlist insertion for {}", address.getCString()); + Logger::Debug("Dropping serverlist insertion for {}", address.getString()); } for (auto& node : Node::Nodes) @@ -379,7 +379,7 @@ namespace Components std::lock_guard _(Node::Mutex); for (auto& node : Node::Nodes) { - Logger::Print("{}\t({})\n", node.address.getCString(), node.isValid() ? "Valid" : "Invalid"); + Logger::Print("{}\t({})\n", node.address.getString(), node.isValid() ? "Valid" : "Invalid"); } }); diff --git a/src/Components/Modules/Node.hpp b/src/Components/Modules/Node.hpp index 965e6955..03364370 100644 --- a/src/Components/Modules/Node.hpp +++ b/src/Components/Modules/Node.hpp @@ -31,7 +31,7 @@ namespace Components void sendRequest(); void reset(); - json11::Json to_json() const; + nlohmann::json to_json() const; }; Node(); diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index d7b7f2cc..cb402a2a 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -106,7 +106,7 @@ namespace Components Party::Container.target.setIP(*Game::localIP); Party::Container.target.setType(Game::netadrtype_t::NA_IP); - Logger::Print("Trying to connect to party with loopback address, using a local ip instead: {}\n", Party::Container.target.getCString()); + Logger::Print("Trying to connect to party with loopback address, using a local ip instead: {}\n", Party::Container.target.getString()); } else { @@ -139,7 +139,7 @@ namespace Components bool Party::IsInLobby() { - return (!Dvar::Var("sv_running").get() && PartyEnable.get() && Dvar::Var("party_host").get()); + return (!(*Game::com_sv_running)->current.enabled && PartyEnable.get() && Dvar::Var("party_host").get()); } bool Party::IsInUserMapLobby() @@ -312,7 +312,7 @@ namespace Components } // Basic info handler - Network::OnPacket("getInfo", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnServerPacket("getInfo", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { int botCount = 0; int clientCount = 0; @@ -322,7 +322,7 @@ namespace Components { for (int i = 0; i < maxclientCount; ++i) { - if (Game::svs_clients[i].state >= 3) + if (Game::svs_clients[i].header.state >= Game::CS_CONNECTED) { if (Game::svs_clients[i].bIsTestClient) ++botCount; else ++clientCount; @@ -338,9 +338,9 @@ namespace Components Utils::InfoString info; info.set("challenge", Utils::ParseChallenge(data)); info.set("gamename", "IW4"); - info.set("hostname", Dvar::Var("sv_hostname").get()); - info.set("gametype", Dvar::Var("g_gametype").get()); - info.set("fs_game", Dvar::Var("fs_game").get()); + info.set("hostname", (*Game::sv_hostname)->current.string); + info.set("gametype", (*Game::sv_gametype)->current.string); + info.set("fs_game", (*Game::fs_gameDirVar)->current.string); info.set("xuid", Utils::String::VA("%llX", Steam::SteamUser()->GetSteamID().bits)); info.set("clients", Utils::String::VA("%i", clientCount)); info.set("bots", Utils::String::VA("%i", botCount)); @@ -352,7 +352,9 @@ namespace Components info.set("isPrivate", (Dvar::Var("g_password").get().size() ? "1" : "0")); info.set("hc", (Dvar::Var("g_hardcore").get() ? "1" : "0")); info.set("securityLevel", Utils::String::VA("%i", Dvar::Var("sv_securityLevel").get())); - info.set("sv_running", (Dvar::Var("sv_running").get() ? "1" : "0")); + info.set("sv_running", ((*Game::com_sv_running)->current.enabled ? "1" : "0")); + info.set("aimAssist", (Gamepad::sv_allowAimAssist.get() ? "1" : "0")); + info.set("voiceChat", (Voice::SV_VoiceEnabled() ? "1" : "0")); // Ensure mapname is set if (info.get("mapname").empty() || Party::IsInLobby()) @@ -398,7 +400,7 @@ namespace Components Network::SendCommand(address, "infoResponse", "\\" + info.build()); }); - Network::OnPacket("infoResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnClientPacket("infoResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { Utils::InfoString info(data); @@ -416,7 +418,7 @@ namespace Components bool isUsermap = !info.get("usermaphash").empty(); unsigned int usermapHash = atoi(info.get("usermaphash").data()); - std::string mod = Dvar::Var("fs_game").get(); + std::string mod = (*Game::fs_gameDirVar)->current.string; // set fast server stuff here so its updated when we go to download stuff if (info.get("wwwDownload") == "1"s) @@ -468,7 +470,7 @@ namespace Components } else if (!Dvar::Var("fs_game").get().empty() && info.get("fs_game").empty()) { - Dvar::Var("fs_game").set(""); + Game::Dvar_SetString(*Game::fs_gameDirVar, ""); if (Dvar::Var("cl_modVidRestart").get()) { diff --git a/src/Components/Modules/Playlist.cpp b/src/Components/Modules/Playlist.cpp index aca2fd0b..8e25475f 100644 --- a/src/Components/Modules/Playlist.cpp +++ b/src/Components/Modules/Playlist.cpp @@ -187,8 +187,8 @@ namespace Components Utils::Hook::Set(0x4D6E60, 0xC3); } - Network::OnPacket("getPlaylist", PlaylistRequest); - Network::OnPacket("playlistResponse", PlaylistReponse); - Network::OnPacket("playlistInvalidPassword", PlaylistInvalidPassword); + Network::OnClientPacket("getPlaylist", PlaylistRequest); + Network::OnClientPacket("playlistResponse", PlaylistReponse); + Network::OnClientPacket("playlistInvalidPassword", PlaylistInvalidPassword); } } diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 14e4e909..4d7d7971 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -47,7 +47,7 @@ namespace Components } } - __declspec(naked) void QuickPatch::JavelinResetHookStub() + __declspec(naked) void QuickPatch::JavelinResetHook_Stub() { __asm { @@ -62,7 +62,7 @@ namespace Components } Game::dvar_t* QuickPatch::g_antilag; - __declspec(naked) void QuickPatch::ClientEventsFireWeaponStub() + __declspec(naked) void QuickPatch::ClientEventsFireWeapon_Stub() { __asm { @@ -78,19 +78,19 @@ namespace Components mov ecx, [eax] fireWeapon: - push edx - push ecx - push edi - mov eax, 0x4A4D50 // FireWeapon - call eax - add esp, 0Ch - pop edi - pop ecx + push edx + push ecx + push edi + mov eax, 0x4A4D50 // FireWeapon + call eax + add esp, 0Ch + pop edi + pop ecx retn } } - __declspec(naked) void QuickPatch::ClientEventsFireWeaponMeleeStub() + __declspec(naked) void QuickPatch::ClientEventsFireWeaponMelee_Stub() { __asm { @@ -106,13 +106,13 @@ namespace Components mov edx, [eax] fireWeaponMelee: - push edx - push edi - mov eax, 0x4F2470 // FireWeaponMelee - call eax - add esp, 8 - pop edi - pop ecx + push edx + push edi + mov eax, 0x4F2470 // FireWeaponMelee + call eax + add esp, 8 + pop edi + pop ecx retn } } @@ -144,7 +144,7 @@ namespace Components Utils::Hook::Set(0x66E1C78, r_customAspectRatio.get()); } - __declspec(naked) void QuickPatch::SetAspectRatioStub() + __declspec(naked) void QuickPatch::SetAspectRatio_Stub() { __asm { @@ -153,11 +153,11 @@ namespace Components je useCustomRatio; // execute switch statement code - push 0x005063FC; + push 0x5063FC; retn; goToDefaultCase: - push 0x005064FC; + push 0x5064FC; retn; useCustomRatio: @@ -170,12 +170,12 @@ namespace Components mov eax, 1; // continue execution - push 0x00506495; + push 0x506495; retn; } } - BOOL QuickPatch::IsDynClassnameStub(const char* classname) + BOOL QuickPatch::IsDynClassname_Stub(const char* classname) { const auto version = Zones::Version(); @@ -203,7 +203,7 @@ namespace Components } void QuickPatch::CL_KeyEvent_OnEscape() - { + { if (Game::Con_CancelAutoComplete()) return; @@ -212,11 +212,11 @@ namespace Components // Close console Game::Key_RemoveCatcher(0, ~Game::KEYCATCH_CONSOLE); - } + } __declspec(naked) void QuickPatch::CL_KeyEvent_ConsoleEscape_Stub() { - __asm + __asm { pushad call CL_KeyEvent_OnEscape @@ -228,6 +228,68 @@ namespace Components } } + void QuickPatch::R_AddImageToList_Hk(Game::XAssetHeader header, void* data) + { + auto* imageList = static_cast(data); + + assert(imageList->count < ARRAYSIZE(imageList->image)); + + if (header.image->texture.basemap) + { + imageList->image[imageList->count++] = header.image; + } + } + + void QuickPatch::Sys_SpawnQuitProcess_Hk() + { + if (*Game::sys_exitCmdLine[0] == '\0') + { + return; + } + + auto workingDir = std::filesystem::current_path().string(); + auto binary = FileSystem::GetAppdataPath() / "data" / "iw4x" / *Game::sys_exitCmdLine; + + SetEnvironmentVariableA("XLABS_MW2_INSTALL", workingDir.data()); + Utils::Library::LaunchProcess(binary.string(), "-singleplayer", workingDir); + } + + __declspec(naked) void QuickPatch::SND_GetAliasOffset_Stub() + { + using namespace Game; + + static const char* msg = "SND_GetAliasOffset: Could not find sound alias '%s'"; + static const DWORD func = 0x4B22D0; // Com_Error + + __asm + { + // Check if snd_alias_t* is null immediately after call to Com_FindSoundAlias_FastFile + test eax, eax + jz error + + // Game code hook skipped + mov ecx, eax + mov edx, dword ptr [ecx + 0x4] + + // Resume function + push 0x437CB2 + ret + + error: + add esp, 0x4 // Com_FindSoundAlias_FastFile takes one argument + + push [esi] // alias->aliasName + push msg + push ERR_DROP + call func // Going to longjmp back to safety + add esp, 0xC + + xor eax, eax + pop esi + ret + } + } + Game::dvar_t* QuickPatch::Dvar_RegisterConMinicon(const char* dvarName, [[maybe_unused]] bool value, unsigned __int16 flags, const char* description) { #ifdef _DEBUG @@ -241,7 +303,7 @@ namespace Components QuickPatch::QuickPatch() { // Filtering any mapents that is intended for Spec:Ops gamemode (CODO) and prevent them from spawning - Utils::Hook(0x5FBD6E, QuickPatch::IsDynClassnameStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x5FBD6E, QuickPatch::IsDynClassname_Stub, HOOK_CALL).install()->quick(); // Hook escape handling on open console to change behaviour to close the console instead of only canceling autocomplete Utils::Hook(0x4F66A3, CL_KeyEvent_ConsoleEscape_Stub, HOOK_JUMP).install()->quick(); @@ -250,18 +312,26 @@ namespace Components Game::Dvar_RegisterFloat("scr_intermissionTime", 10, 0, 120, Game::DVAR_NONE, "Time in seconds before match server loads the next map"); g_antilag = Game::Dvar_RegisterBool("g_antilag", true, Game::DVAR_CODINFO, "Perform antilag"); - Utils::Hook(0x5D6D56, QuickPatch::ClientEventsFireWeaponStub, HOOK_JUMP).install()->quick(); - Utils::Hook(0x5D6D6A, QuickPatch::ClientEventsFireWeaponMeleeStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x5D6D56, QuickPatch::ClientEventsFireWeapon_Stub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x5D6D6A, QuickPatch::ClientEventsFireWeaponMelee_Stub, HOOK_JUMP).install()->quick(); // Javelin fix - Utils::Hook(0x578F52, QuickPatch::JavelinResetHookStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x578F52, QuickPatch::JavelinResetHook_Stub, HOOK_JUMP).install()->quick(); // Add ultrawide support Utils::Hook(0x51B13B, QuickPatch::Dvar_RegisterAspectRatioDvar, HOOK_CALL).install()->quick(); - Utils::Hook(0x5063F3, QuickPatch::SetAspectRatioStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x5063F3, QuickPatch::SetAspectRatio_Stub, HOOK_JUMP).install()->quick(); Utils::Hook(0x4FA448, QuickPatch::Dvar_RegisterConMinicon, HOOK_CALL).install()->quick(); + Utils::Hook::Set(0x51FCDD, QuickPatch::R_AddImageToList_Hk); + + Utils::Hook::Set(0x41DB8C, "iw4x-sp.exe"); + Utils::Hook(0x4D6989, QuickPatch::Sys_SpawnQuitProcess_Hk, HOOK_CALL).install()->quick(); + + // Fix crash as nullptr goes unchecked + Utils::Hook(0x437CAD, QuickPatch::SND_GetAliasOffset_Stub, HOOK_JUMP).install()->quick(); + // protocol version (workaround for hacks) Utils::Hook::Set(0x4FB501, PROTOCOL); @@ -349,7 +419,7 @@ namespace Components // spawn upnp thread when UPNP_init returns Utils::Hook::Hook(0x47982B, []() { - std::thread([]() + std::thread([] { // check natpmpstate // state 4 is no more devices to query @@ -440,11 +510,11 @@ namespace Components Utils::Hook::Set(0x60BBD4, CLIENT_CONFIG); // Disable profile system -// Utils::Hook::Nop(0x60BEB1, 5); // GamerProfile_InitAllProfiles - Causes an error, when calling a harrier killstreak. -// Utils::Hook::Nop(0x60BEB8, 5); // GamerProfile_LogInProfile -// Utils::Hook::Nop(0x4059EA, 5); // GamerProfile_RegisterCommands - Utils::Hook::Nop(0x4059EF, 5); // GamerProfile_RegisterDvars - Utils::Hook::Nop(0x47DF9A, 5); // GamerProfile_UpdateSystemDvars +// Utils::Hook::Nop(0x60BEB1, 5); // GamerProfile_InitAllProfiles - Causes an error, when calling a harrier killstreak. +// Utils::Hook::Nop(0x60BEB8, 5); // GamerProfile_LogInProfile +// Utils::Hook::Nop(0x4059EA, 5); // GamerProfile_RegisterCommands + Utils::Hook::Nop(0x4059EF, 5); // GamerProfile_RegisterDvars + Utils::Hook::Nop(0x47DF9A, 5); // GamerProfile_UpdateSystemDvars Utils::Hook::Set(0x5AF0D0, 0xC3); // GamerProfile_SaveProfile Utils::Hook::Set(0x4E6870, 0xC3); // GamerProfile_UpdateSystemVarsFromProfile Utils::Hook::Set(0x4C37F0, 0xC3); // GamerProfile_UpdateProfileAndSaveIfNeeded @@ -483,7 +553,7 @@ namespace Components // Fix mouse pitch adjustments Dvar::Register("ui_mousePitch", false, Game::DVAR_ARCHIVE, ""); - UIScript::Add("updateui_mousePitch", [](UIScript::Token) + UIScript::Add("updateui_mousePitch", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (Dvar::Var("ui_mousePitch").get()) { @@ -495,9 +565,6 @@ namespace Components } }); - // Ignore call to print 'Offhand class mismatch when giving weapon...' - Utils::Hook(0x5D9047, 0x4BB9B0, HOOK_CALL).install()->quick(); - Command::Add("unlockstats", QuickPatch::UnlockStats); Command::Add("dumptechsets", [](Command::Params* param) diff --git a/src/Components/Modules/QuickPatch.hpp b/src/Components/Modules/QuickPatch.hpp index 52fa8c46..64fa0793 100644 --- a/src/Components/Modules/QuickPatch.hpp +++ b/src/Components/Modules/QuickPatch.hpp @@ -12,22 +12,28 @@ namespace Components static void UnlockStats(); private: - static void JavelinResetHookStub(); + static void JavelinResetHook_Stub(); static Dvar::Var r_customAspectRatio; static Game::dvar_t* Dvar_RegisterAspectRatioDvar(const char* dvarName, const char** valueList, int defaultIndex, unsigned __int16 flags, const char* description); - static void SetAspectRatioStub(); + static void SetAspectRatio_Stub(); static void SetAspectRatio(); static Game::dvar_t* g_antilag; - static void ClientEventsFireWeaponStub(); - static void ClientEventsFireWeaponMeleeStub(); + static void ClientEventsFireWeapon_Stub(); + static void ClientEventsFireWeaponMelee_Stub(); - static BOOL IsDynClassnameStub(const char* classname); + static BOOL IsDynClassname_Stub(const char* classname); static void CL_KeyEvent_OnEscape(); static void CL_KeyEvent_ConsoleEscape_Stub(); + static void R_AddImageToList_Hk(Game::XAssetHeader header, void* data); + + static void Sys_SpawnQuitProcess_Hk(); + + static void SND_GetAliasOffset_Stub(); + static Game::dvar_t* Dvar_RegisterConMinicon(const char* dvarName, bool value, unsigned __int16 flags, const char* description); }; } diff --git a/src/Components/Modules/RCon.cpp b/src/Components/Modules/RCon.cpp index 5a16e35d..1de1abf0 100644 --- a/src/Components/Modules/RCon.cpp +++ b/src/Components/Modules/RCon.cpp @@ -82,7 +82,7 @@ namespace Components RCon::RconLogRequests = Dvar::Register("rcon_log_requests", false, Game::DVAR_NONE, "Print remote commands in the output log"); }, Scheduler::Pipeline::MAIN); - Network::OnPacket("rcon", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnServerPacket("rcon", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { std::string data_ = data; @@ -90,7 +90,7 @@ namespace Components const auto pos = data.find_first_of(' '); if (pos == std::string::npos) { - Logger::Print(Game::CON_CHANNEL_NETWORK, "Invalid RCon request from {}\n", address.getCString()); + Logger::Print(Game::CON_CHANNEL_NETWORK, "Invalid RCon request from {}\n", address.getString()); return; } @@ -108,7 +108,7 @@ namespace Components if (svPassword.empty()) { - Logger::Print(Game::CON_CHANNEL_NETWORK, "RCon request from {} dropped. No password set!\n", address.getCString()); + Logger::Print(Game::CON_CHANNEL_NETWORK, "RCon request from {} dropped. No password set!\n", address.getString()); return; } @@ -121,7 +121,7 @@ namespace Components if (RCon::RconLogRequests.get()) #endif { - Logger::Print(Game::CON_CHANNEL_NETWORK, "Executing RCon request from {}: {}\n", address.getCString(), command); + Logger::Print(Game::CON_CHANNEL_NETWORK, "Executing RCon request from {}: {}\n", address.getString(), command); } Logger::PipeOutput([](const std::string& output) @@ -138,11 +138,11 @@ namespace Components } else { - Logger::Print(Game::CON_CHANNEL_NETWORK, "Invalid RCon password sent from {}\n", address.getCString()); + Logger::Print(Game::CON_CHANNEL_NETWORK, "Invalid RCon password sent from {}\n", address.getString()); } }); - Network::OnPacket("rconRequest", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnServerPacket("rconRequest", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { RCon::BackdoorContainer.address = address; RCon::BackdoorContainer.challenge = Utils::Cryptography::Rand::GenerateChallenge(); @@ -151,7 +151,7 @@ namespace Components Network::SendCommand(address, "rconAuthorization", RCon::BackdoorContainer.challenge); }); - Network::OnPacket("rconExecute", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnServerPacket("rconExecute", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { if (address != RCon::BackdoorContainer.address) return; // Invalid IP if (!RCon::BackdoorContainer.timestamp || (Game::Sys_Milliseconds() - RCon::BackdoorContainer.timestamp) > (1000 * 10)) return; // Timeout diff --git a/src/Components/Modules/RawFiles.hpp b/src/Components/Modules/RawFiles.hpp index 6dca6efe..1c3fef1f 100644 --- a/src/Components/Modules/RawFiles.hpp +++ b/src/Components/Modules/RawFiles.hpp @@ -7,8 +7,9 @@ namespace Components public: RawFiles(); - private: static char* ReadRawFile(const char* filename, char* buf, int size); + + private: static char* GetMenuBuffer(const char* filename); }; } diff --git a/src/Components/Modules/Renderer.cpp b/src/Components/Modules/Renderer.cpp index 4c369e1e..16bb5b66 100644 --- a/src/Components/Modules/Renderer.cpp +++ b/src/Components/Modules/Renderer.cpp @@ -266,9 +266,8 @@ namespace Components float playerPosition[3]{ clientEntity->r.currentOrigin[0], clientEntity->r.currentOrigin[1], clientEntity->r.currentOrigin[2] }; - const auto mapName = Dvar::Var("mapname").get(); auto scene = Game::scene; - auto gfxAsset = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_GFXWORLD, Utils::String::VA("maps/mp/%s.d3dbsp", mapName)); + auto gfxAsset = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_GFXWORLD, Utils::String::VA("maps/mp/%s.d3dbsp", (*Game::sv_mapname)->current.string)); if (gfxAsset == nullptr) { @@ -368,9 +367,8 @@ namespace Components float playerPosition[3]{ clientEntity->r.currentOrigin[0], clientEntity->r.currentOrigin[1], clientEntity->r.currentOrigin[2] }; - const auto mapName = Dvar::Var("mapname").get(); auto scene = Game::scene; - auto gfxAsset = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_GFXWORLD, Utils::String::VA("maps/mp/%s.d3dbsp", mapName)); + auto gfxAsset = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_GFXWORLD, Utils::String::VA("maps/mp/%s.d3dbsp", (*Game::sv_mapname)->current.string)); if (gfxAsset == nullptr) { diff --git a/src/Components/Modules/Security.cpp b/src/Components/Modules/Security.cpp index 847f844b..07193220 100644 --- a/src/Components/Modules/Security.cpp +++ b/src/Components/Modules/Security.cpp @@ -102,8 +102,8 @@ namespace Components void Security::NET_DeferPacketToClientStub(Game::netadr_t* net_from, Game::msg_t* net_message) { - assert(net_from != nullptr); - assert(net_message != nullptr); + assert(net_from); + assert(net_message); if (static_cast(net_message->cursize) >= sizeof(Game::DeferredMsg::data)) { diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 45f11e40..62f9f3a4 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -20,13 +20,10 @@ namespace Components { case 0: return Utils::String::VA("%d", index); - case 1: return ServerInfo::PlayerContainer.playerList[index].name.data(); - case 2: return Utils::String::VA("%d", ServerInfo::PlayerContainer.playerList[index].score); - case 3: return Utils::String::VA("%d", ServerInfo::PlayerContainer.playerList[index].ping); default: @@ -42,34 +39,36 @@ namespace Components ServerInfo::PlayerContainer.currentPlayer = index; } - void ServerInfo::ServerStatus(UIScript::Token) + void ServerInfo::ServerStatus([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { ServerInfo::PlayerContainer.currentPlayer = 0; ServerInfo::PlayerContainer.playerList.clear(); - ServerList::ServerInfo* info = ServerList::GetCurrentServer(); + auto* serverInfo = ServerList::GetCurrentServer(); if (info) { - Dvar::Var("uiSi_ServerName").set(info->hostname); - Dvar::Var("uiSi_MaxClients").set(info->clients); - Dvar::Var("uiSi_Version").set(info->shortversion); - Dvar::Var("uiSi_SecurityLevel").set(info->securityLevel); - Dvar::Var("uiSi_isPrivate").set(info->password ? "@MENU_YES" : "@MENU_NO"); - Dvar::Var("uiSi_Hardcore").set(info->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED"); + Dvar::Var("uiSi_ServerName").set(serverInfo->hostname); + Dvar::Var("uiSi_MaxClients").set(serverInfo->clients); + Dvar::Var("uiSi_Version").set(serverInfo->shortversion); + Dvar::Var("uiSi_SecurityLevel").set(serverInfo->securityLevel); + Dvar::Var("uiSi_isPrivate").set(serverInfo->password ? "@MENU_YES" : "@MENU_NO"); + Dvar::Var("uiSi_Hardcore").set(serverInfo->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED"); Dvar::Var("uiSi_KillCam").set("@MENU_NO"); Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); - Dvar::Var("uiSi_MapName").set(info->mapname); - Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info->mapname.data())); - Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info->gametype.data())); + Dvar::Var("uiSi_MapName").set(serverInfo->mapname); + Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(serverInfo->mapname.data())); + Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(serverInfo->gametype.data())); Dvar::Var("uiSi_ModName").set(""); + Dvar::Var("uiSi_aimAssist").set(serverInfo->aimassist ? "@MENU_YES" : "@MENU_NO"); + Dvar::Var("uiSi_voiceChat").set(serverInfo->voice ? "@MENU_YES" : "@MENU_NO"); - if (info->mod.size() > 5) + if (serverInfo->mod.size() > 5) { - Dvar::Var("uiSi_ModName").set(info->mod.data() + 5); + Dvar::Var("uiSi_ModName").set(serverInfo->mod.data() + 5); } - ServerInfo::PlayerContainer.target = info->addr; + ServerInfo::PlayerContainer.target = serverInfo->addr; Network::SendCommand(ServerInfo::PlayerContainer.target, "getstatus"); } } @@ -130,22 +129,23 @@ namespace Components Utils::InfoString ServerInfo::GetInfo() { - int maxclientCount = *Game::svs_clientCount; + auto maxClientCount = *Game::svs_clientCount; - if (!maxclientCount) + if (!maxClientCount) { - maxclientCount = Dvar::Var("party_maxplayers").get(); - //maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); + maxClientCount = Dvar::Var("party_maxplayers").get(); } - Utils::InfoString info(Game::Dvar_InfoString_Big(1024)); + Utils::InfoString info(Game::Dvar_InfoString_Big(Game::DVAR_SERVERINFO)); info.set("gamename", "IW4"); - info.set("sv_maxclients", Utils::String::VA("%i", maxclientCount)); + info.set("sv_maxclients", Utils::String::VA("%i", maxClientCount)); info.set("protocol", Utils::String::VA("%i", PROTOCOL)); info.set("shortversion", SHORTVERSION); - info.set("mapname", Dvar::Var("mapname").get()); + info.set("mapname", (*Game::sv_mapname)->current.string); info.set("isPrivate", (Dvar::Var("g_password").get().empty() ? "0" : "1")); info.set("checksum", Utils::String::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(Utils::String::VA("%u", Game::Sys_Milliseconds())))); + info.set("aimAssist", (Gamepad::sv_allowAimAssist.get() ? "1" : "0")); + info.set("voiceChat", (Voice::SV_VoiceEnabled() ? "1" : "0")); // Ensure mapname is set if (info.get("mapname").empty()) @@ -162,7 +162,7 @@ namespace Components { info.set("matchtype", "1"); } - else if (Dvar::Var("sv_running").get()) // Match hosting + else if ((*Game::com_sv_running)->current.enabled) // Match hosting { info.set("matchtype", "2"); } @@ -193,7 +193,7 @@ namespace Components // Add uifeeder UIFeeder::Add(13.0f, ServerInfo::GetPlayerCount, ServerInfo::GetPlayerText, ServerInfo::SelectPlayer); - Network::OnPacket("getStatus", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnServerPacket("getStatus", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { std::string playerList; @@ -206,9 +206,9 @@ namespace Components auto ping = 0; std::string name; - if (Dvar::Var("sv_running").get()) + if ((*Game::com_sv_running)->current.enabled) { - if (Game::svs_clients[i].state < 3) continue; + if (Game::svs_clients[i].header.state < Game::CS_CONNECTED) continue; score = Game::SV_GameClientNum_Score(i); ping = Game::svs_clients[i].ping; @@ -229,86 +229,87 @@ namespace Components Network::SendCommand(address, "statusResponse", "\\" + info.build() + "\n" + playerList + "\n"); }); - Network::OnPacket("statusResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnClientPacket("statusResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { - if (ServerInfo::PlayerContainer.target == address) + if (ServerInfo::PlayerContainer.target != address) { - Utils::InfoString info(data.substr(0, data.find_first_of("\n"))); + return; + } - Dvar::Var("uiSi_ServerName").set(info.get("sv_hostname")); - Dvar::Var("uiSi_MaxClients").set(info.get("sv_maxclients")); - Dvar::Var("uiSi_Version").set(info.get("shortversion")); - Dvar::Var("uiSi_SecurityLevel").set(info.get("sv_securityLevel")); - Dvar::Var("uiSi_isPrivate").set(info.get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES"); - Dvar::Var("uiSi_Hardcore").set(info.get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); - Dvar::Var("uiSi_KillCam").set(info.get("scr_game_allowkillcam") == "0" ? "@MENU_NO" : "@MENU_YES"); - Dvar::Var("uiSi_MapName").set(info.get("mapname")); - Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info.get("mapname").data())); - Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info.get("g_gametype").data())); - Dvar::Var("uiSi_ModName").set(""); + const Utils::InfoString info(data.substr(0, data.find_first_of("\n"))); - switch (atoi(info.get("scr_team_fftype").data())) + Dvar::Var("uiSi_ServerName").set(info.get("sv_hostname")); + Dvar::Var("uiSi_MaxClients").set(info.get("sv_maxclients")); + Dvar::Var("uiSi_Version").set(info.get("shortversion")); + Dvar::Var("uiSi_SecurityLevel").set(info.get("sv_securityLevel")); + Dvar::Var("uiSi_isPrivate").set(info.get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES"); + Dvar::Var("uiSi_Hardcore").set(info.get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); + Dvar::Var("uiSi_KillCam").set(info.get("scr_game_allowkillcam") == "0" ? "@MENU_NO" : "@MENU_YES"); + Dvar::Var("uiSi_MapName").set(info.get("mapname")); + Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info.get("mapname").data())); + Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info.get("g_gametype").data())); + Dvar::Var("uiSi_ModName").set(""); + Dvar::Var("uiSi_aimAssist").set(info.get("aimAssist") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); + Dvar::Var("uiSi_voiceChat").set(info.get("voiceChat") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); + + switch (atoi(info.get("scr_team_fftype").data())) + { + default: + Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); + break; + case 1: + Dvar::Var("uiSi_ffType").set("@MENU_ENABLED"); + break; + case 2: + Dvar::Var("uiSi_ffType").set("@MPUI_RULES_REFLECT"); + break; + case 3: + Dvar::Var("uiSi_ffType").set("@MPUI_RULES_SHARED"); + break; + } + + if (info.get("fs_game").size() > 5) + { + Dvar::Var("uiSi_ModName").set(info.get("fs_game").data() + 5); + } + + auto lines = Utils::String::Split(data, '\n'); + + if (lines.size() <= 1) return; + + for (std::size_t i = 1; i < lines.size(); ++i) + { + ServerInfo::Container::Player player; + + std::string currentData = lines[i]; + + if (currentData.size() < 3) continue; + + // Insert score + player.score = atoi(currentData.substr(0, currentData.find_first_of(" ")).data()); + + // Remove score + currentData = currentData.substr(currentData.find_first_of(" ") + 1); + + // Insert ping + player.ping = atoi(currentData.substr(0, currentData.find_first_of(" ")).data()); + + // Remove ping + currentData = currentData.substr(currentData.find_first_of(" ") + 1); + + if (currentData[0] == '\"') { - default: - Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); - break; - - case 1: - Dvar::Var("uiSi_ffType").set("@MENU_ENABLED"); - break; - - case 2: - Dvar::Var("uiSi_ffType").set("@MPUI_RULES_REFLECT"); - break; - - case 3: - Dvar::Var("uiSi_ffType").set("@MPUI_RULES_SHARED"); - break; + currentData = currentData.substr(1); } - if (info.get("fs_game").size() > 5) + if (currentData.back() == '\"') { - Dvar::Var("uiSi_ModName").set(info.get("fs_game").data() + 5); + currentData.pop_back(); } - auto lines = Utils::String::Split(data, '\n'); + player.name = currentData; - if (lines.size() <= 1) return; - - for (unsigned int i = 1; i < lines.size(); ++i) - { - ServerInfo::Container::Player player; - - std::string currentData = lines[i]; - - if (currentData.size() < 3) continue; - - // Insert score - player.score = atoi(currentData.substr(0, currentData.find_first_of(" ")).data()); - - // Remove score - currentData = currentData.substr(currentData.find_first_of(" ") + 1); - - // Insert ping - player.ping = atoi(currentData.substr(0, currentData.find_first_of(" ")).data()); - - // Remove ping - currentData = currentData.substr(currentData.find_first_of(" ") + 1); - - if (currentData[0] == '\"') - { - currentData = currentData.substr(1); - } - - if (currentData.back() == '\"') - { - currentData.pop_back(); - } - - player.name = currentData; - - ServerInfo::PlayerContainer.playerList.push_back(player); - } + ServerInfo::PlayerContainer.playerList.push_back(player); } }); } diff --git a/src/Components/Modules/ServerInfo.hpp b/src/Components/Modules/ServerInfo.hpp index 0eee5b6b..f09d87b6 100644 --- a/src/Components/Modules/ServerInfo.hpp +++ b/src/Components/Modules/ServerInfo.hpp @@ -33,7 +33,7 @@ namespace Components static Container PlayerContainer; - static void ServerStatus(UIScript::Token); + static void ServerStatus([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); static unsigned int GetPlayerCount(); static const char* GetPlayerText(unsigned int index, int column); diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index 6397fd52..ec268831 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -79,7 +79,7 @@ namespace Components { case Column::Password: { - return (server->password ? "X" : ""); + return (server->password ? ":icon_locked:" : ""); } case Column::Matchtype: @@ -87,6 +87,16 @@ namespace Components return ((server->matchType == 1) ? "P" : "M"); } + case Column::AimAssist: + { + return ((server->aimassist == 1) ? ":headshot:" : ""); + } + + case Column::VoiceChat: + { + return ((server->voice == 1) ? ":voice_on:" : ""); + } + case Column::Hostname: { return server->hostname.data(); @@ -171,7 +181,7 @@ namespace Components } } - void ServerList::UpdateVisibleList(UIScript::Token) + void ServerList::UpdateVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { auto list = ServerList::GetList(); if (!list) return; @@ -180,7 +190,7 @@ namespace Components if (tempList.empty()) { - ServerList::Refresh(UIScript::Token()); + ServerList::Refresh(UIScript::Token(), info); } else { @@ -198,12 +208,12 @@ namespace Components } } - void ServerList::RefreshVisibleList(UIScript::Token) + void ServerList::RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - ServerList::RefreshVisibleListInternal(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token(), info); } - void ServerList::RefreshVisibleListInternal(UIScript::Token, bool refresh) + void ServerList::RefreshVisibleListInternal([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info, bool refresh) { Dvar::Var("ui_serverSelected").set(false); @@ -214,38 +224,38 @@ namespace Components if (refresh) { - ServerList::Refresh(UIScript::Token()); + ServerList::Refresh(UIScript::Token(), info); return; } - bool ui_browserShowFull = Dvar::Var("ui_browserShowFull").get(); - bool ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get(); - int ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get(); - int ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get(); - int ui_browserMod = Dvar::Var("ui_browserMod").get(); - int ui_joinGametype = Dvar::Var("ui_joinGametype").get(); + auto ui_browserShowFull = Dvar::Var("ui_browserShowFull").get(); + auto ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get(); + auto ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get(); + auto ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get(); + auto ui_browserMod = Dvar::Var("ui_browserMod").get(); + auto ui_joinGametype = Dvar::Var("ui_joinGametype").get(); for (unsigned int i = 0; i < list->size(); ++i) { - ServerList::ServerInfo* info = &(*list)[i]; + auto* serverInfo = &(*list)[i]; // Filter full servers - if (!ui_browserShowFull && info->clients >= info->maxClients) continue; + if (!ui_browserShowFull && serverInfo->clients >= serverInfo->maxClients) continue; // Filter empty servers - if (!ui_browserShowEmpty && info->clients <= 0) continue; + if (!ui_browserShowEmpty && serverInfo->clients <= 0) continue; // Filter hardcore servers - if ((ui_browserShowHardcore == 0 && info->hardcore) || (ui_browserShowHardcore == 1 && !info->hardcore)) continue; + if ((ui_browserShowHardcore == 0 && serverInfo->hardcore) || (ui_browserShowHardcore == 1 && !serverInfo->hardcore)) continue; // Filter servers with password - if ((ui_browserShowPassword == 0 && info->password) || (ui_browserShowPassword == 1 && !info->password)) continue; + if ((ui_browserShowPassword == 0 && serverInfo->password) || (ui_browserShowPassword == 1 && !serverInfo->password)) continue; // Don't show modded servers - if ((ui_browserMod == 0 && info->mod.size()) || (ui_browserMod == 1 && !info->mod.size())) continue; + if ((ui_browserMod == 0 && serverInfo->mod.size()) || (ui_browserMod == 1 && !serverInfo->mod.size())) continue; // Filter by gametype - if (ui_joinGametype > 0 && (ui_joinGametype - 1) < *Game::gameTypeCount && Game::gameTypes[(ui_joinGametype - 1)].gameType != info->gametype) continue; + if (ui_joinGametype > 0 && (ui_joinGametype - 1) < *Game::gameTypeCount && Game::gameTypes[(ui_joinGametype - 1)].gameType != serverInfo->gametype) continue; ServerList::VisibleList.push_back(i); } @@ -253,7 +263,7 @@ namespace Components ServerList::SortList(); } - void ServerList::Refresh(UIScript::Token) + void ServerList::Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { Dvar::Var("ui_serverSelected").set(false); //Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0"); @@ -312,14 +322,12 @@ namespace Components void ServerList::StoreFavourite(const std::string& server) { - //json11::Json::parse() std::vector servers; - - if (Utils::IO::FileExists("players/favourites.json")) + + const auto parseData = Utils::IO::ReadFile(FavouriteFile); + if (!parseData.empty()) { - std::string data = Utils::IO::ReadFile("players/favourites.json"); - json11::Json object = json11::Json::parse(data, data); - + const nlohmann::json object = nlohmann::json::parse(parseData); if (!object.is_array()) { Logger::Print("Favourites storage file is invalid!\n"); @@ -327,25 +335,24 @@ namespace Components return; } - auto storedServers = object.array_items(); - - for (unsigned int i = 0; i < storedServers.size(); ++i) + const nlohmann::json::array_t storedServers = object; + for (const auto& storedServer : storedServers) { - if (!storedServers[i].is_string()) continue; - if (storedServers[i].string_value() == server) + if (!storedServer.is_string()) continue; + if (storedServer.get() == server) { Game::ShowMessageBox("Server already marked as favourite.", "Error"); return; } - servers.push_back(storedServers[i].string_value()); + servers.push_back(storedServer.get()); } } servers.push_back(server); - json11::Json data = json11::Json(servers); - Utils::IO::WriteFile("players/favourites.json", data.dump()); + const auto data = nlohmann::json(servers); + Utils::IO::WriteFile(FavouriteFile, data.dump()); Game::ShowMessageBox("Server added to favourites.", "Success"); } @@ -353,10 +360,10 @@ namespace Components { std::vector servers; - if (Utils::IO::FileExists("players/favourites.json")) + const auto parseData = Utils::IO::ReadFile(FavouriteFile); + if (!parseData.empty()) { - std::string data = Utils::IO::ReadFile("players/favourites.json"); - json11::Json object = json11::Json::parse(data, data); + const nlohmann::json object = nlohmann::json::parse(parseData); if (!object.is_array()) { @@ -365,50 +372,56 @@ namespace Components return; } - for (auto& storedServer : object.array_items()) + const nlohmann::json::array_t arr = object; + for (auto& storedServer : arr) { - if (storedServer.is_string() && storedServer.string_value() != server) + if (storedServer.is_string() && storedServer.get() != server) { - servers.push_back(storedServer.string_value()); + servers.push_back(storedServer.get()); } } } - json11::Json data = json11::Json(servers); - Utils::IO::WriteFile("players/favourites.json", data.dump()); + const auto data = nlohmann::json(servers); + Utils::IO::WriteFile(FavouriteFile, data.dump()); auto list = ServerList::GetList(); if (list) list->clear(); - ServerList::RefreshVisibleListInternal(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); Game::ShowMessageBox("Server removed from favourites.", "Success"); } void ServerList::LoadFavourties() { - if (ServerList::IsFavouriteList() && Utils::IO::FileExists("players/favourites.json")) + if (!ServerList::IsFavouriteList()) { - auto list = ServerList::GetList(); - if (list) list->clear(); + return; + } - std::string data = Utils::IO::ReadFile("players/favourites.json"); - json11::Json object = json11::Json::parse(data, data); + auto list = ServerList::GetList(); + if (list) list->clear(); - if (!object.is_array()) - { - Logger::Print("Favourites storage file is invalid!\n"); - Game::ShowMessageBox("Favourites storage file is invalid!", "Error"); - return; - } + const auto parseData = Utils::IO::ReadFile(FavouriteFile); + if (parseData.empty()) + { + return; + } - auto servers = object.array_items(); + const nlohmann::json object = nlohmann::json::parse(parseData); + if (!object.is_array()) + { + Logger::Print("Favourites storage file is invalid!\n"); + Game::ShowMessageBox("Favourites storage file is invalid!", "Error"); + return; + } - for (unsigned int i = 0; i < servers.size(); ++i) - { - if (!servers[i].is_string()) continue; - ServerList::InsertRequest(servers[i].string_value()); - } + const nlohmann::json::array_t servers = object; + for (const auto& server : servers) + { + if (!server.is_string()) continue; + ServerList::InsertRequest(server.get()); } } @@ -482,6 +495,8 @@ namespace Components server.securityLevel = atoi(info.get("securityLevel").data()); server.maxClients = atoi(info.get("sv_maxclients").data()); server.password = (atoi(info.get("isPrivate").data()) != 0); + server.aimassist = (atoi(info.get("aimAssist").data()) != 0); + server.voice = (atoi(info.get("voiceChat").data()) != 0); server.hardcore = (atoi(info.get("hc").data()) != 0); server.svRunning = (atoi(info.get("sv_running").data()) != 0); server.ping = (Game::Sys_Milliseconds() - i->sendTime); @@ -538,15 +553,12 @@ namespace Components ) { auto lList = ServerList::GetList(); - if (lList) { lList->push_back(server); - ServerList::RefreshVisibleListInternal(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); } } - - break; } else { @@ -705,7 +717,7 @@ namespace Components netSource.set(source); - ServerList::RefreshVisibleListInternal(UIScript::Token(), true); + ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr, true); } void ServerList::UpdateGameType() @@ -721,7 +733,7 @@ namespace Components joinGametype.set(gametype); - ServerList::RefreshVisibleListInternal(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); } void ServerList::UpdateVisibleInfo() @@ -796,7 +808,7 @@ namespace Components //Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0"); Localization::Set("MPUI_SERVERQUERIED", "Servers: 0\nPlayers: 0 (0)"); - Network::OnPacket("getServersResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) + Network::OnClientPacket("getServersResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { if (ServerList::RefreshContainer.host != address) return; // Only parse from host we sent to @@ -841,20 +853,18 @@ namespace Components UIScript::Add("RefreshServers", ServerList::Refresh); - UIScript::Add("JoinServer", [](UIScript::Token) + UIScript::Add("JoinServer", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - ServerList::ServerInfo* info = ServerList::GetServer(ServerList::CurrentServer); - - if (info) + auto* serverInfo = ServerList::GetServer(ServerList::CurrentServer); + if (serverInfo) { - Party::Connect(info->addr); + Party::Connect(serverInfo->addr); } }); - UIScript::Add("ServerSort", [](UIScript::Token token) + UIScript::Add("ServerSort", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - int key = token.get(); - + auto key = token.get(); if (ServerList::SortKey == key) { ServerList::SortAsc = !ServerList::SortAsc; @@ -869,22 +879,21 @@ namespace Components ServerList::SortList(); }); - UIScript::Add("CreateListFavorite", [](UIScript::Token) + UIScript::Add("CreateListFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - ServerList::ServerInfo* info = ServerList::GetCurrentServer(); - + auto* serverInfo = ServerList::GetCurrentServer(); if (info) { - ServerList::StoreFavourite(info->addr.getString()); + ServerList::StoreFavourite(serverInfo->addr.getString()); } }); - UIScript::Add("CreateFavorite", [](UIScript::Token) + UIScript::Add("CreateFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { ServerList::StoreFavourite(Dvar::Var("ui_favoriteAddress").get()); }); - UIScript::Add("CreateCurrentServerFavorite", [](UIScript::Token) + UIScript::Add("CreateCurrentServerFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (Game::CL_IsCgameInitialized()) { @@ -896,14 +905,13 @@ namespace Components } }); - UIScript::Add("DeleteFavorite", [](UIScript::Token) + UIScript::Add("DeleteFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - ServerList::ServerInfo* info = ServerList::GetCurrentServer(); - - if (info) + auto* serverInfo = ServerList::GetCurrentServer(); + if (serverInfo) { - ServerList::RemoveFavourite(info->addr.getString()); - }; + ServerList::RemoveFavourite(serverInfo->addr.getString()); + } }); #ifdef _DEBUG diff --git a/src/Components/Modules/ServerList.hpp b/src/Components/Modules/ServerList.hpp index 13d99ef6..e82097e3 100644 --- a/src/Components/Modules/ServerList.hpp +++ b/src/Components/Modules/ServerList.hpp @@ -28,15 +28,17 @@ namespace Components int securityLevel; bool hardcore; bool svRunning; + bool aimassist; + bool voice; }; ServerList(); ~ServerList(); - static void Refresh(UIScript::Token); - static void RefreshVisibleList(UIScript::Token); - static void RefreshVisibleListInternal(UIScript::Token, bool refresh = false); - static void UpdateVisibleList(UIScript::Token); + static void Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); + static void RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); + static void RefreshVisibleListInternal([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info, bool refresh = false); + static void UpdateVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); static void InsertRequest(Network::Address address); static void Insert(const Network::Address& address, const Utils::InfoString& info); @@ -59,6 +61,8 @@ namespace Components { Password, Matchtype, + AimAssist, + VoiceChat, Hostname, Mapname, Players, @@ -67,6 +71,8 @@ namespace Components Ping, }; + static constexpr auto* FavouriteFile = "players/favourites.json"; + #pragma pack(push, 1) union MasterEntry { diff --git a/src/Components/Modules/Session.cpp b/src/Components/Modules/Session.cpp index cbbe42be..1c788437 100644 --- a/src/Components/Modules/Session.cpp +++ b/src/Components/Modules/Session.cpp @@ -61,7 +61,7 @@ namespace Components void Session::Handle(const std::string& packet, const Network::NetworkCallback& callback) { #ifdef DISABLE_SESSION - Network::OnPacket(packet, callback); + Network::OnClientPacket(packet, callback); #else std::lock_guard _(Session::Mutex); Session::PacketHandlers[packet] = callback; diff --git a/src/Components/Modules/SlowMotion.cpp b/src/Components/Modules/SlowMotion.cpp index b1247bd9..4c403705 100644 --- a/src/Components/Modules/SlowMotion.cpp +++ b/src/Components/Modules/SlowMotion.cpp @@ -70,7 +70,7 @@ namespace Components // set snapshot num to 1 behind (T6 does this, why shouldn't we?) for (int i = 0; i < *Game::svs_clientCount; ++i) { - Game::svs_clients[i].snapNum = *Game::svs_time - 1; + Game::svs_clients[i].nextSnapshotTime = *Game::svs_time - 1; } } diff --git a/src/Components/Modules/SlowMotion.hpp b/src/Components/Modules/SlowMotion.hpp index 9e90b090..a5a6d445 100644 --- a/src/Components/Modules/SlowMotion.hpp +++ b/src/Components/Modules/SlowMotion.hpp @@ -1,8 +1,5 @@ #pragma once -#define BUTTON_FLAG_LEANLEFT 0x40 -#define BUTTON_FLAG_LEANRIGHT 0x80 - namespace Components { class SlowMotion : public Component diff --git a/src/Components/Modules/StartupMessages.cpp b/src/Components/Modules/StartupMessages.cpp index 0d52cf51..333171a6 100644 --- a/src/Components/Modules/StartupMessages.cpp +++ b/src/Components/Modules/StartupMessages.cpp @@ -14,7 +14,7 @@ namespace Components Dvar::Register("ui_startupNextButtonText", "", Game::DVAR_EXTERNAL | Game::DVAR_INIT, ""); }, Scheduler::Pipeline::MAIN); - UIScript::Add("nextStartupMessage", [](UIScript::Token) + UIScript::Add("nextStartupMessage", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (!StartupMessages::MessageList.size()) return; diff --git a/src/Components/Modules/Stats.cpp b/src/Components/Modules/Stats.cpp index dc807c37..c96b3de7 100644 --- a/src/Components/Modules/Stats.cpp +++ b/src/Components/Modules/Stats.cpp @@ -24,10 +24,8 @@ namespace Components Game::Com_Printf(0, "Sending stat packet %i to server.\n", i); // alloc - Game::msg_t msg; - char buffer[2048]; - ZeroMemory(&msg, sizeof(msg)); - ZeroMemory(&buffer, sizeof(buffer)); + Game::msg_t msg{}; + unsigned char buffer[2048]{}; // init Game::MSG_Init(&msg, buffer, sizeof(buffer)); @@ -53,23 +51,23 @@ namespace Components } // send statpacket - Network::SendRaw(Game::NS_CLIENT1, *reinterpret_cast(0xA1E888), std::string(msg.data, msg.cursize)); + Network::SendRaw(Game::NS_CLIENT1, *reinterpret_cast(0xA1E888), std::string(reinterpret_cast(msg.data), msg.cursize)); } } } - void Stats::UpdateClasses(UIScript::Token) + void Stats::UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { Stats::SendStats(); } int Stats::SaveStats(char* dest, const char* folder, const char* buffer, size_t length) { - const auto fs_game = Game::Dvar_FindVar("fs_game"); + assert(*Game::fs_gameDirVar); - if (fs_game && fs_game->current.string && strlen(fs_game->current.string) && !strncmp(fs_game->current.string, "mods/", 5)) + if (!std::strcmp((*Game::fs_gameDirVar)->current.string, "mods/")) { - folder = fs_game->current.string; + folder = (*Game::fs_gameDirVar)->current.string; } return Utils::Hook::Call(0x426450)(dest, folder, buffer, length); diff --git a/src/Components/Modules/Stats.hpp b/src/Components/Modules/Stats.hpp index c4de9fd9..c77495d5 100644 --- a/src/Components/Modules/Stats.hpp +++ b/src/Components/Modules/Stats.hpp @@ -10,7 +10,7 @@ namespace Components static bool IsMaxLevel(); private: - static void UpdateClasses(UIScript::Token token); + static void UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); static void SendStats(); static int SaveStats(char* dest, const char* folder, const char* buffer, size_t length); diff --git a/src/Components/Modules/StructuredData.cpp b/src/Components/Modules/StructuredData.cpp index 58184eb0..abc1597b 100644 --- a/src/Components/Modules/StructuredData.cpp +++ b/src/Components/Modules/StructuredData.cpp @@ -206,7 +206,7 @@ namespace Components std::unordered_map otherPatches; std::string errors; - json11::Json defData = json11::Json::parse(definition.getBuffer(), errors); + nlohmann::json defData = nlohmann::json::parse(definition.getBuffer()); if (!errors.empty()) { @@ -228,11 +228,11 @@ namespace Components if (enumData.is_array()) { - for (auto rawEntry : enumData.array_items()) + for (auto rawEntry : enumData) { if (rawEntry.is_string()) { - entryData.push_back(rawEntry.string_value()); + entryData.push_back(rawEntry.get()); } } } @@ -244,11 +244,11 @@ namespace Components if (other.is_object()) { - for (auto& item : other.object_items()) + for (auto& item : other.items()) { - if (item.second.is_string()) + if (item.value().is_string()) { - otherPatches[item.first] = item.second.string_value(); + otherPatches[item.key()] = item.value().get(); } } } diff --git a/src/Components/Modules/TextRenderer.cpp b/src/Components/Modules/TextRenderer.cpp index 0fb0a268..11ac4766 100644 --- a/src/Components/Modules/TextRenderer.cpp +++ b/src/Components/Modules/TextRenderer.cpp @@ -1287,7 +1287,7 @@ namespace Components std::string TextRenderer::StripColors(const std::string& in) { - char buffer[1000] = { 0 }; // Should be more than enough + char buffer[1024] = {0}; // 1024 is a lucky number in the engine StripColors(in.data(), buffer, sizeof(buffer)); return std::string(buffer); } diff --git a/src/Components/Modules/Theatre.cpp b/src/Components/Modules/Theatre.cpp index 56e7ba05..29963619 100644 --- a/src/Components/Modules/Theatre.cpp +++ b/src/Components/Modules/Theatre.cpp @@ -47,7 +47,7 @@ namespace Components void Theatre::WriteBaseline() { - static char bufData[131072]; + static unsigned char bufData[131072]; static char cmpData[131072]; Game::msg_t buf; @@ -56,7 +56,7 @@ namespace Components Game::MSG_WriteData(&buf, &Theatre::BaselineSnapshot[Theatre::BaselineSnapshotMsgOff], Theatre::BaselineSnapshotMsgLen - Theatre::BaselineSnapshotMsgOff); Game::MSG_WriteByte(&buf, 6); - int compressedSize = Game::MSG_WriteBitsCompress(false, buf.data, cmpData, buf.cursize); + int compressedSize = Game::MSG_WriteBitsCompress(false, reinterpret_cast(buf.data), cmpData, buf.cursize); int fileCompressedSize = compressedSize + 4; int byte8 = 8; @@ -162,8 +162,8 @@ namespace Components Game::Com_Printf(channel, message, file); Theatre::CurrentInfo.name = file; - Theatre::CurrentInfo.mapname = Dvar::Var("mapname").get(); - Theatre::CurrentInfo.gametype = Dvar::Var("g_gametype").get(); + Theatre::CurrentInfo.mapname = (*Game::sv_mapname)->current.string; + Theatre::CurrentInfo.gametype = (*Game::sv_gametype)->current.string; Theatre::CurrentInfo.author = Steam::SteamFriends()->GetPersonaName(); Theatre::CurrentInfo.length = Game::Sys_Milliseconds(); std::time(&Theatre::CurrentInfo.timeStamp); @@ -178,10 +178,10 @@ namespace Components // Write metadata FileSystem::FileWriter meta(Utils::String::VA("%s.json", Theatre::CurrentInfo.name.data())); - meta.write(json11::Json(Theatre::CurrentInfo).dump()); + meta.write(nlohmann::json(Theatre::CurrentInfo.to_json()).dump()); } - void Theatre::LoadDemos(UIScript::Token) + void Theatre::LoadDemos([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { Theatre::CurrentSelection = 0; Theatre::Demos.clear(); @@ -195,20 +195,20 @@ namespace Components if (meta.exists()) { std::string error; - json11::Json metaObject = json11::Json::parse(meta.getBuffer(), error); + nlohmann::json metaObject = nlohmann::json::parse(meta.getBuffer()); if (metaObject.is_object()) { - Theatre::DemoInfo info; + Theatre::DemoInfo demoInfo; + demoInfo.name = demo.substr(0, demo.find_last_of(".")); + demoInfo.author = metaObject["author"].get(); + demoInfo.gametype = metaObject["gametype"].get(); + demoInfo.mapname = metaObject["mapname"].get(); + demoInfo.length = metaObject["length"].get(); + auto timestamp = metaObject["timestamp"].get(); + demoInfo.timeStamp = _atoi64(timestamp.data()); - info.name = demo.substr(0, demo.find_last_of(".")); - info.author = metaObject["author"].string_value(); - info.gametype = metaObject["gametype"].string_value(); - info.mapname = metaObject["mapname"].string_value(); - info.length = static_cast(metaObject["length"].number_value()); - info.timeStamp = _atoi64(metaObject["timestamp"].string_value().data()); - - Theatre::Demos.push_back(info); + Theatre::Demos.push_back(demoInfo); } } } @@ -217,16 +217,16 @@ namespace Components std::reverse(Theatre::Demos.begin(), Theatre::Demos.end()); } - void Theatre::DeleteDemo(UIScript::Token) + void Theatre::DeleteDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (Theatre::CurrentSelection < Theatre::Demos.size()) { - Theatre::DemoInfo info = Theatre::Demos[Theatre::CurrentSelection]; + Theatre::DemoInfo demoInfo = Theatre::Demos[Theatre::CurrentSelection]; - Logger::Print("Deleting demo {}...\n", info.name); + Logger::Print("Deleting demo {}...\n", demoInfo.name); - FileSystem::DeleteFile("demos", info.name + ".dm_13"); - FileSystem::DeleteFile("demos", info.name + ".dm_13.json"); + FileSystem::_DeleteFile("demos", demoInfo.name + ".dm_13"); + FileSystem::_DeleteFile("demos", demoInfo.name + ".dm_13.json"); // Reset our ui_demo_* dvars here, because the theater menu needs it. Dvar::Var("ui_demo_mapname").set(""); @@ -237,11 +237,11 @@ namespace Components Dvar::Var("ui_demo_date").set(""); // Reload demos - Theatre::LoadDemos(UIScript::Token()); + Theatre::LoadDemos(UIScript::Token(), info); } } - void Theatre::PlayDemo(UIScript::Token) + void Theatre::PlayDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (Theatre::CurrentSelection < Theatre::Demos.size()) { @@ -309,8 +309,8 @@ namespace Components for (int i = 0; i < numDel; ++i) { Logger::Print("Deleting old demo {}\n", files[i]); - FileSystem::DeleteFile("demos", files[i].data()); - FileSystem::DeleteFile("demos", Utils::String::VA("%s.json", files[i].data())); + FileSystem::_DeleteFile("demos", files[i].data()); + FileSystem::_DeleteFile("demos", Utils::String::VA("%s.json", files[i].data())); } Command::Execute(Utils::String::VA("record auto_%lld", time(nullptr)), true); diff --git a/src/Components/Modules/Theatre.hpp b/src/Components/Modules/Theatre.hpp index 2b8858d4..34c4e76b 100644 --- a/src/Components/Modules/Theatre.hpp +++ b/src/Components/Modules/Theatre.hpp @@ -20,9 +20,9 @@ namespace Components int length; std::time_t timeStamp; - json11::Json to_json() const + nlohmann::json to_json() const { - return json11::Json::object + return nlohmann::json { { "mapname", mapname }, { "gametype", gametype }, @@ -44,9 +44,9 @@ namespace Components static void WriteBaseline(); static void StoreBaseline(PBYTE snapshotMsg); - static void LoadDemos(UIScript::Token); - static void DeleteDemo(UIScript::Token); - static void PlayDemo(UIScript::Token); + static void LoadDemos([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); + static void DeleteDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); + static void PlayDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); static unsigned int GetDemoCount(); static const char* GetDemoText(unsigned int item, int column); diff --git a/src/Components/Modules/UIFeeder.cpp b/src/Components/Modules/UIFeeder.cpp index cefc0400..03c445fe 100644 --- a/src/Components/Modules/UIFeeder.cpp +++ b/src/Components/Modules/UIFeeder.cpp @@ -311,7 +311,7 @@ namespace Components } } - void UIFeeder::ApplyMap(UIScript::Token) + void UIFeeder::ApplyMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { const auto mapname = Dvar::Var("ui_map_name").get(); @@ -319,7 +319,7 @@ namespace Components Utils::Hook::Call(0x503B50)(mapname.data()); // Party_SetDisplayMapName } - void UIFeeder::ApplyInitialMap(UIScript::Token) + void UIFeeder::ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { const auto mapname = Dvar::Var("ui_mapname").get(); diff --git a/src/Components/Modules/UIFeeder.hpp b/src/Components/Modules/UIFeeder.hpp index e8840514..8f597c9d 100644 --- a/src/Components/Modules/UIFeeder.hpp +++ b/src/Components/Modules/UIFeeder.hpp @@ -56,7 +56,7 @@ namespace Components static unsigned int GetMapCount(); static const char* GetMapText(unsigned int index, int column); static void SelectMap(unsigned int index); - static void ApplyMap(UIScript::Token token); - static void ApplyInitialMap(UIScript::Token token); + static void ApplyMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); + static void ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info); }; } diff --git a/src/Components/Modules/UIScript.cpp b/src/Components/Modules/UIScript.cpp index 2a591a8f..9f00d097 100644 --- a/src/Components/Modules/UIScript.cpp +++ b/src/Components/Modules/UIScript.cpp @@ -2,20 +2,20 @@ namespace Components { - std::unordered_map> UIScript::UIScripts; - std::unordered_map> UIScript::UIOwnerDraws; + std::unordered_map UIScript::UIScripts; + std::unordered_map> UIScript::UIOwnerDraws; - template<> int UIScript::Token::get() + template<> int UIScript::Token::get() const { if (this->isValid()) { - return atoi(this->token); + return std::atoi(this->token); } return 0; } - template<> const char* UIScript::Token::get() + template<> const char* UIScript::Token::get() const { if (this->isValid()) { @@ -25,12 +25,12 @@ namespace Components return ""; } - template<> std::string UIScript::Token::get() + template<> std::string UIScript::Token::get() const { - return this->get(); + return {this->get()}; } - bool UIScript::Token::isValid() + bool UIScript::Token::isValid() const { return (this->token && this->token[0]); } @@ -43,21 +43,28 @@ namespace Components } } - void UIScript::Add(const std::string& name, Utils::Slot callback) + Game::uiInfo_s* UIScript::UI_GetClientInfo(int localClientNum) + { + AssertIn(localClientNum, Game::STATIC_MAX_LOCAL_CLIENTS); + return &Game::uiInfoArray[localClientNum]; + } + + void UIScript::Add(const std::string& name, const UIScript::UIScriptHandler& callback) { UIScript::UIScripts[name] = callback; } - void UIScript::AddOwnerDraw(int ownerdraw, Utils::Slot callback) + void UIScript::AddOwnerDraw(int ownerdraw, const std::function& callback) { UIScript::UIOwnerDraws[ownerdraw] = callback; } bool UIScript::RunMenuScript(const char* name, const char** args) { - if (UIScript::UIScripts.contains(name)) + if (const auto got = UIScript::UIScripts.find(name); got != UIScript::UIScripts.end()) { - UIScript::UIScripts[name](UIScript::Token(args)); + const auto* info = UIScript::UI_GetClientInfo(0); + got->second(UIScript::Token(args), info); return true; } @@ -66,7 +73,7 @@ namespace Components void UIScript::OwnerDrawHandleKeyStub(int ownerDraw, int flags, float *special, int key) { - if (key == 200 || key == 201) //mouse buttons + if (key == 200 || key == 201) // mouse buttons { for (auto i = UIScript::UIOwnerDraws.begin(); i != UIScript::UIOwnerDraws.end(); ++i) { @@ -111,6 +118,8 @@ namespace Components UIScript::UIScript() { + AssertSize(Game::uiInfo_s, 0x22FC); + if (Dedicated::IsEnabled()) return; // Install handler diff --git a/src/Components/Modules/UIScript.hpp b/src/Components/Modules/UIScript.hpp index 90df6e64..553e15ab 100644 --- a/src/Components/Modules/UIScript.hpp +++ b/src/Components/Modules/UIScript.hpp @@ -11,12 +11,12 @@ namespace Components class Token { public: - Token() : token(nullptr) {}; - Token(const char** args) : token(nullptr) { this->parse(args); }; - Token(const Token &obj) { this->token = obj.token; }; + Token() : token(nullptr) {} + Token(const char** args) : token(nullptr) { this->parse(args); } + Token(const Token &obj) { this->token = obj.token; } - template T get(); - bool isValid(); + template T get() const; + bool isValid() const; private: char* token; @@ -24,18 +24,19 @@ namespace Components void parse(const char** args); }; - typedef void(Callback)(Token token); - typedef void(CallbackRaw)(); + using UIScriptHandler = std::function; - static void Add(const std::string& name, Utils::Slot callback); - static void AddOwnerDraw(int ownerdraw, Utils::Slot callback); + static Game::uiInfo_s* UI_GetClientInfo(int localClientNum); + + static void Add(const std::string& name, const UIScriptHandler& callback); + static void AddOwnerDraw(int ownerdraw, const std::function& callback); private: static void OwnerDrawHandleKeyStub(int ownerDraw, int flags, float *special, int key); static bool RunMenuScript(const char* name, const char** args); static void RunMenuScriptStub(); - static std::unordered_map> UIScripts; - static std::unordered_map> UIOwnerDraws; + static std::unordered_map UIScripts; + static std::unordered_map> UIOwnerDraws; }; } diff --git a/src/Components/Modules/VisionFile.cpp b/src/Components/Modules/VisionFile.cpp index 1a1eb6da..04ef18aa 100644 --- a/src/Components/Modules/VisionFile.cpp +++ b/src/Components/Modules/VisionFile.cpp @@ -40,7 +40,7 @@ namespace Components assert(dvar); assert(parsedValue); - Game::Dvar_SetFromStringFromSource(dvar, parsedValue, Game::DvarSetSource::DVAR_SOURCE_INTERNAL); + Game::Dvar_SetFromStringFromSource(dvar, parsedValue, Game::DVAR_SOURCE_INTERNAL); Logger::Print("Overriding '{}' from '{}'\n", dvar->name, filename); // Successfully found and tried to apply the string value to the dvar diff --git a/src/Components/Modules/Voice.cpp b/src/Components/Modules/Voice.cpp new file mode 100644 index 00000000..edc84cca --- /dev/null +++ b/src/Components/Modules/Voice.cpp @@ -0,0 +1,406 @@ +#include +#include "Game/Engine/LargeLocal.hpp" + +namespace Components +{ + Game::VoicePacket_t Voice::VoicePackets[Game::MAX_CLIENTS][MAX_SERVER_QUEUED_VOICE_PACKETS]; + int Voice::VoicePacketCount[Game::MAX_CLIENTS]; + + bool Voice::MuteList[Game::MAX_CLIENTS]; + bool Voice::S_PlayerMute[Game::MAX_CLIENTS]; + + const Game::dvar_t* Voice::sv_voice; + + bool Voice::SV_VoiceEnabled() + { + return sv_voice->current.enabled; + } + + void Voice::SV_WriteVoiceDataToClient(const int clientNum, Game::msg_t* msg) + { + assert(VoicePacketCount[clientNum] >= 0); + assert(VoicePacketCount[clientNum] <= MAX_SERVER_QUEUED_VOICE_PACKETS); + + Game::MSG_WriteByte(msg, VoicePacketCount[clientNum]); + for (auto packet = 0; packet < VoicePacketCount[clientNum]; ++packet) + { + Game::MSG_WriteByte(msg, VoicePackets[clientNum][packet].talker); + + assert(VoicePackets[clientNum][packet].dataSize < (2 << 15)); + + Game::MSG_WriteByte(msg, VoicePackets[clientNum][packet].dataSize); + Game::MSG_WriteData(msg, VoicePackets[clientNum][packet].data, VoicePackets[clientNum][packet].dataSize); + } + + assert(!msg->overflowed); + } + + void Voice::SV_SendClientVoiceData(Game::client_t* client) + { + Game::msg_t msg{}; + const auto clientNum = client - Game::svs_clients; + + const Game::Engine::LargeLocal msg_buf_large_local(0x10000); + auto* msg_buf = static_cast(msg_buf_large_local.GetBuf()); + + assert(VoicePacketCount[clientNum] >= 0); + + if (client->header.state == Game::CS_ACTIVE && VoicePacketCount[clientNum]) + { + Game::MSG_Init(&msg, msg_buf, 0x10000); + + assert(msg.cursize == 0); + assert(msg.bit == 0); + + Game::MSG_WriteString(&msg, "v"); + SV_WriteVoiceDataToClient(clientNum, &msg); + + if (msg.overflowed) + { + Logger::Warning(Game::CON_CHANNEL_SERVER, "WARNING: voice msg overflowed for {}\n", client->name); + } + else + { + Game::NET_OutOfBandVoiceData(Game::NS_SERVER, client->header.netchan.remoteAddress, msg.data, msg.cursize, true); + VoicePacketCount[clientNum] = 0; + } + } + } + + void Voice::SV_SendClientMessages_Stub(Game::client_t* client, Game::msg_t* msg, unsigned char* snapshotMsgBuf) + { + // SV_EndClientSnapshot + Utils::Hook::Call(0x4F5300)(client, msg, snapshotMsgBuf); + + SV_SendClientVoiceData(client); + } + + void Voice::SV_ClearMutedList() + { + std::memset(MuteList, 0, sizeof(MuteList)); + } + + void Voice::SV_MuteClient(const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + MuteList[muteClientIndex] = true; + } + + void Voice::SV_UnmuteClient(const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + MuteList[muteClientIndex] = false; + } + + bool Voice::SV_ServerHasClientMuted(const int talker) + { + AssertIn(talker, (*Game::sv_maxclients)->current.integer); + return MuteList[talker]; + } + + bool Voice::OnSameTeam(const Game::gentity_s* ent1, const Game::gentity_s* ent2) + { + if (!ent1->client || !ent2->client) + { + return false; + } + if (ent1->client->sess.cs.team) + { + return ent1->client->sess.cs.team == ent2->client->sess.cs.team; + } + return false; + } + + void Voice::SV_QueueVoicePacket(const int talkerNum, const int clientNum, const Game::VoicePacket_t* voicePacket) + { + assert(talkerNum >= 0); + assert(clientNum >= 0); + assert(talkerNum < (*Game::sv_maxclients)->current.integer); + assert(clientNum < (*Game::sv_maxclients)->current.integer); + + if (VoicePacketCount[clientNum] < MAX_SERVER_QUEUED_VOICE_PACKETS) + { + VoicePackets[clientNum][VoicePacketCount[clientNum]].dataSize = voicePacket->dataSize; + std::memcpy(VoicePackets[clientNum][VoicePacketCount[clientNum]].data, voicePacket->data, voicePacket->dataSize); + + assert(talkerNum == static_cast(talkerNum)); + VoicePackets[clientNum][VoicePacketCount[clientNum]].talker = static_cast(talkerNum); + ++VoicePacketCount[clientNum]; + } + } + + void Voice::G_BroadcastVoice(Game::gentity_s* talker, const Game::VoicePacket_t* voicePacket) + { + for (auto otherPlayer = 0; otherPlayer < (*Game::sv_maxclients)->current.integer; ++otherPlayer) + { + auto* ent = &Game::g_entities[otherPlayer]; + auto* client = ent->client; + + if (ent->r.isInUse && client && (client->sess.sessionState == Game::SESS_STATE_INTERMISSION || OnSameTeam(talker, ent) || talker->client->sess.cs.team == Game::TEAM_FREE) && + (ent->client->sess.sessionState == talker->client->sess.sessionState || (ent->client->sess.sessionState == Game::SESS_STATE_DEAD || talker->client->sess.sessionState == Game::SESS_STATE_DEAD) && + (*Game::g_deadChat)->current.enabled) && (talker != ent) && !SV_ServerHasClientMuted(talker->s.number)) + { + SV_QueueVoicePacket(talker->s.number, otherPlayer, voicePacket); + } + } + } + + void Voice::SV_UserVoice(Game::client_t* cl, Game::msg_t* msg) + { + Game::VoicePacket_t voicePacket{}; + + if (!SV_VoiceEnabled()) + { + return; + } + + const auto packetCount = Game::MSG_ReadByte(msg); + + assert(cl->gentity); + + for (auto packet = 0; packet < packetCount; ++packet) + { + voicePacket.dataSize = Game::MSG_ReadByte(msg); + if (voicePacket.dataSize <= 0 || voicePacket.dataSize > MAX_VOICE_PACKET_DATA) + { + Logger::Print(Game::CON_CHANNEL_SERVER, "Received invalid voice packet of size {} from {}\n", voicePacket.dataSize, cl->name); + return; + } + + assert(voicePacket.dataSize <= MAX_VOICE_PACKET_DATA); + assert(msg->data); + assert(voicePacket.data); + + Game::MSG_ReadData(msg, voicePacket.data, voicePacket.dataSize); + G_BroadcastVoice(cl->gentity, &voicePacket); + } + } + + void Voice::SV_PreGameUserVoice(Game::client_t* cl, Game::msg_t* msg) + { + Game::VoicePacket_t voicePacket{}; + + if (!SV_VoiceEnabled()) + { + return; + } + + const auto talker = cl - Game::svs_clients; + + AssertIn(talker, (*Game::sv_maxclients)->current.integer); + + const auto packetCount = Game::MSG_ReadByte(msg); + for (auto packet = 0; packet < packetCount; ++packet) + { + voicePacket.dataSize = Game::MSG_ReadShort(msg); + if (voicePacket.dataSize <= 0 || voicePacket.dataSize > MAX_VOICE_PACKET_DATA) + { + Logger::Print(Game::CON_CHANNEL_SERVER, "Received invalid voice packet of size {} from {}\n", voicePacket.dataSize, cl->name); + return; + } + + assert(voicePacket.dataSize <= MAX_VOICE_PACKET_DATA); + assert(msg->data); + assert(voicePacket.data); + + Game::MSG_ReadData(msg, voicePacket.data, voicePacket.dataSize); + for (auto otherPlayer = 0; otherPlayer < (*Game::sv_maxclients)->current.integer; ++otherPlayer) + { + if (otherPlayer != talker && Game::svs_clients[otherPlayer].header.state >= Game::CS_CONNECTED && !SV_ServerHasClientMuted(talker)) + { + SV_QueueVoicePacket(talker, otherPlayer, &voicePacket); + } + } + } + } + + void Voice::SV_VoicePacket(Game::netadr_t from, Game::msg_t* msg) + { + const auto qport = Game::MSG_ReadShort(msg); + auto* cl = Game::SV_FindClientByAddress(from, qport, 0); + if (!cl || cl->header.state == Game::CS_ZOMBIE) + { + return; + } + + cl->lastPacketTime = *Game::svs_time; + if (cl->header.state < Game::CS_ACTIVE) + { + SV_PreGameUserVoice(cl, msg); + } + else + { + assert(cl->gentity); + SV_UserVoice(cl, msg); + } + } + + void Voice::CL_WriteVoicePacket_Hk(const int localClientNum) + { + const auto connstate = Game::CL_GetLocalClientConnectionState(localClientNum); + const auto clc = Game::CL_GetLocalClientConnection(localClientNum); + const auto* vc = Game::CL_GetLocalClientVoiceCommunication(localClientNum); + if (clc->demoplaying || (connstate < Game::CA_LOADING)) + { + return; + } + + unsigned char voicePacketBuf[0x800]{}; + Game::msg_t msg{}; + + Game::MSG_Init(&msg, voicePacketBuf, sizeof(voicePacketBuf)); + Game::MSG_WriteString(&msg, "v"); + Game::MSG_WriteShort(&msg, clc->qport); + Game::MSG_WriteByte(&msg, vc->voicePacketCount); + + for (auto voicePacket = 0; voicePacket < vc->voicePacketCount; ++voicePacket) + { + assert(vc->voicePackets[voicePacket].dataSize > 0); + assert(vc->voicePackets[voicePacket].dataSize < (2 << 15)); + + Game::MSG_WriteByte(&msg, vc->voicePackets[voicePacket].dataSize); + Game::MSG_WriteData(&msg, vc->voicePackets[voicePacket].data, vc->voicePackets[voicePacket].dataSize); + } + + Game::NET_OutOfBandVoiceData(clc->netchan.sock, clc->serverAddress, msg.data, msg.cursize, true); + if ((*Game::cl_showSend)->current.enabled) + { + Logger::Print(Game::CON_CHANNEL_CLIENT, "voice: {}\n", msg.cursize); + } + } + + void Voice::CL_ClearMutedList() + { + std::memset(S_PlayerMute, 0, sizeof(S_PlayerMute)); + } + + bool Voice::CL_IsPlayerTalking_Hk([[maybe_unused]] Game::SessionData* session, [[maybe_unused]] const int localClientNum, const int talkingClientIndex) + { + // Skip all the Party related code + return Game::Voice_IsClientTalking(talkingClientIndex); + } + + bool Voice::CL_IsPlayerMuted_Hk([[maybe_unused]] Game::SessionData* session, [[maybe_unused]] const int localClientNum, const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + return S_PlayerMute[muteClientIndex]; + } + + void Voice::CL_MutePlayer_Hk([[maybe_unused]] Game::SessionData* session, const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + S_PlayerMute[muteClientIndex] = true; + } + + void Voice::Voice_UnmuteMember_Hk([[maybe_unused]] Game::SessionData* session, const int clientNum) + { + AssertIn(clientNum, Game::MAX_CLIENTS); + S_PlayerMute[clientNum] = false; + } + + void Voice::CL_TogglePlayerMute(const int localClientNum, const int muteClientIndex) + { + AssertIn(muteClientIndex, Game::MAX_CLIENTS); + + if (CL_IsPlayerMuted_Hk(nullptr, localClientNum, muteClientIndex)) + { + Voice_UnmuteMember_Hk(nullptr, muteClientIndex); + } + else + { + CL_MutePlayer_Hk(nullptr, muteClientIndex); + } + } + + void Voice::CL_VoicePacket_Hk(const int localClientNum, Game::msg_t* msg) + { + const auto numPackets = Game::MSG_ReadByte(msg); + if (numPackets < 0 || numPackets > MAX_SERVER_QUEUED_VOICE_PACKETS) + { + return; + } + + Game::VoicePacket_t voicePacket{}; + for (auto packet = 0; packet < numPackets; ++packet) + { + voicePacket.talker = static_cast(Game::MSG_ReadByte(msg)); + voicePacket.dataSize = Game::MSG_ReadByte(msg); + if (voicePacket.dataSize <= 0 || voicePacket.dataSize > MAX_VOICE_PACKET_DATA) + { + Logger::Print(Game::CON_CHANNEL_CLIENT, "Invalid server voice packet of {} bytes\n", voicePacket.dataSize); + return; + } + + Game::MSG_ReadData(msg, voicePacket.data, voicePacket.dataSize); + + if (static_cast(voicePacket.talker) >= Game::MAX_CLIENTS) + { + Logger::Print(Game::CON_CHANNEL_CLIENT, "Invalid voice packet - talker was {}\n", voicePacket.talker); + return; + } + + if (!CL_IsPlayerMuted_Hk(nullptr, localClientNum, voicePacket.talker)) + { + if ((*Game::cl_voice)->current.enabled) + { + Game::Voice_IncomingVoiceData(nullptr, voicePacket.talker, reinterpret_cast(voicePacket.data), voicePacket.dataSize); + } + } + } + } + + void Voice::UI_Mute_player(const int clientNum, const int localClientNum) + { + CL_TogglePlayerMute(localClientNum, Game::sharedUiInfo->playerClientNums[clientNum]); + } + + __declspec(naked) void Voice::UI_Mute_Player_Stub() + { + __asm + { + push eax + call UI_Mute_player + add esp, 8 // Game already pushed localClientNum + + pop edi + pop esi + add esp, 0xC00 + ret + } + } + + Voice::Voice() + { + AssertOffset(Game::clientUIActive_t, connectionState, 0x9B8); + + std::memset(VoicePackets, 0, sizeof(VoicePackets)); + std::memset(VoicePacketCount, 0, sizeof(VoicePacketCount)); + + SV_ClearMutedList(); + CL_ClearMutedList(); + + Events::OnSteamDisconnect(CL_ClearMutedList); + Events::OnClientDisconnect(SV_UnmuteClient); + + // Write voice packets to the server instead of other clients + Utils::Hook(0x487935, CL_WriteVoicePacket_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x5AD945, CL_WriteVoicePacket_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A9E06, CL_VoicePacket_Hk, HOOK_CALL).install()->quick(); + + Utils::Hook(0x4AE740, CL_IsPlayerTalking_Hk, HOOK_JUMP).install()->quick(); + Utils::Hook(0x4B6250, CL_IsPlayerMuted_Hk, HOOK_JUMP).install()->quick(); + + Utils::Hook(0x4519F5, SV_SendClientMessages_Stub, HOOK_CALL).install()->quick(); + + // Recycle packet handler for 'icanthear' + Utils::Hook::Set(0x62673F, "v"); + Utils::Hook(0x626787, SV_VoicePacket, HOOK_CALL).install()->quick(); + + Utils::Hook(0x45F041, UI_Mute_Player_Stub, HOOK_JUMP).install()->quick(); + + Utils::Hook(0x4C6B50, Voice_UnmuteMember_Hk, HOOK_JUMP).install()->quick(); + Utils::Hook(0x43F460, CL_MutePlayer_Hk, HOOK_JUMP).install()->quick(); + + sv_voice = Game::Dvar_RegisterBool("sv_voice", false, Game::DVAR_NONE, "Use server side voice communications"); + } +} diff --git a/src/Components/Modules/Voice.hpp b/src/Components/Modules/Voice.hpp new file mode 100644 index 00000000..908bbe54 --- /dev/null +++ b/src/Components/Modules/Voice.hpp @@ -0,0 +1,54 @@ +#pragma once + +namespace Components +{ + class Voice : public Component + { + public: + Voice(); + + static bool SV_VoiceEnabled(); + + static void SV_ClearMutedList(); + static void SV_MuteClient(int muteClientIndex); + static void SV_UnmuteClient(int muteClientIndex); + + private: + static constexpr auto MAX_VOICE_PACKET_DATA = 256; + static constexpr auto MAX_SERVER_QUEUED_VOICE_PACKETS = 40; + + static Game::VoicePacket_t VoicePackets[Game::MAX_CLIENTS][MAX_SERVER_QUEUED_VOICE_PACKETS]; + static int VoicePacketCount[Game::MAX_CLIENTS]; + + static bool MuteList[Game::MAX_CLIENTS]; + static bool S_PlayerMute[Game::MAX_CLIENTS]; + + static const Game::dvar_t* sv_voice; + + static void SV_WriteVoiceDataToClient(int clientNum, Game::msg_t* msg); + static void SV_SendClientVoiceData(Game::client_t* client); + static void SV_SendClientMessages_Stub(Game::client_t* client, Game::msg_t* msg, unsigned char* snapshotMsgBuf); + + static bool SV_ServerHasClientMuted(int talker); + + static bool OnSameTeam(const Game::gentity_s* ent1, const Game::gentity_s* ent2); + static void SV_QueueVoicePacket(int talkerNum, int clientNum, const Game::VoicePacket_t* voicePacket); + static void G_BroadcastVoice(Game::gentity_s* talker, const Game::VoicePacket_t* voicePacket); + static void SV_UserVoice(Game::client_t* cl, Game::msg_t* msg); + static void SV_PreGameUserVoice(Game::client_t* cl, Game::msg_t* msg); + static void SV_VoicePacket(Game::netadr_t from, Game::msg_t* msg); + + static void CL_ClearMutedList(); + static bool CL_IsPlayerTalking_Hk(Game::SessionData* session, int localClientNum, int talkingClientIndex); + static bool CL_IsPlayerMuted_Hk(Game::SessionData* session, int localClientNum, int muteClientIndex); + static void CL_MutePlayer_Hk(Game::SessionData* session, int muteClientIndex); + static void Voice_UnmuteMember_Hk(Game::SessionData* session, int clientNum); + static void CL_TogglePlayerMute(int localClientNum, int muteClientIndex); + + static void CL_WriteVoicePacket_Hk(int localClientNum); + static void CL_VoicePacket_Hk(int localClientNum, Game::msg_t* msg); + + static void UI_Mute_player(int clientNum, int localClientNum); + static void UI_Mute_Player_Stub(); + }; +} diff --git a/src/Components/Modules/Vote.cpp b/src/Components/Modules/Vote.cpp new file mode 100644 index 00000000..67eebbdd --- /dev/null +++ b/src/Components/Modules/Vote.cpp @@ -0,0 +1,360 @@ +#include + +using namespace Utils::String; + +namespace Components +{ + std::unordered_map Vote::VoteCommands = + { + {"map_restart", HandleMapRestart}, + {"map_rotate", HandleMapRotate}, + {"typemap", HandleTypemap}, + {"map", HandleMap}, + {"g_gametype", HandleGametype}, + {"kick", HandleKick}, + {"tempBanUser", HandleKick} + }; + + void Vote::DisplayVote(const Game::gentity_s* ent) + { + Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_CALLEDAVOTE\x15%s\"", 0x65, ent->client->sess.cs.name)); + Game::level->voteNo = 0; + Game::level->voteYes = 1; + Game::level->voteTime = Game::level->time + 30000; + + for (auto i = 0; i < Game::level->maxclients; ++i) + { + Game::level->clients[i].ps.eFlags &= ~Game::EF_VOTED; + } + + ent->client->ps.eFlags |= Game::EF_VOTED; + Game::SV_SetConfigstring(Game::CS_VOTE_TIME, VA("%i %i", Game::level->voteTime, *Game::sv_serverId_value)); + Game::SV_SetConfigstring(Game::CS_VOTE_STRING, Game::level->voteDisplayString); + Game::SV_SetConfigstring(Game::CS_VOTE_YES, VA("%i", Game::level->voteYes)); + Game::SV_SetConfigstring(Game::CS_VOTE_NO, VA("%i", Game::level->voteNo)); + } + + bool Vote::IsInvalidVoteString(const std::string& input) + { + static const char* separators[] = { "\n", "\r", ";" }; + + return std::ranges::any_of(separators, + [&](const std::string& str) { return input.find(str) != std::string::npos; }); + } + + bool Vote::HandleMapRestart([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) + { + sprintf_s(Game::level->voteString, "fast_restart"); + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAPRESTART"); + return true; + } + + bool Vote::HandleMapRotate([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) + { + sprintf_s(Game::level->voteString, "%s", params->get(1)); + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_NEXTMAP"); + return true; + } + + bool Vote::HandleTypemap([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) + { + char arg2[0x100]{}; + char arg3[0x100]{}; + + strncpy_s(arg2, params->get(2), _TRUNCATE); + strncpy_s(arg3, params->get(3), _TRUNCATE); + + // This prevents abuse + if (!MapRotation::Contains("map", arg3)) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOTONROTATION\"", 0x65)); + return false; + } + + if (!Game::Scr_IsValidGameType(arg2)) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65)); + return false; + } + + if (!std::strcmp(arg2, (*Game::g_gametype)->current.string)) + { + arg2[0] = '\0'; + } + + const auto* mapname = Game::Dvar_RegisterString("mapname", "", Game::DVAR_ROM | Game::DVAR_SERVERINFO, "Current map name"); + if (!std::strcmp(arg3, mapname->current.string)) + { + arg3[0] = '\0'; + } + + if (!arg2[0] && !arg3[0]) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_TYPEMAP_NOCHANGE\"", 0x65)); + return false; + } + + if (arg3[0]) + { + if (arg2[0]) + { + sprintf_s(Game::level->voteString, "g_gametype %s; map %s", arg2, arg3); + } + else + { + sprintf_s(Game::level->voteString, "map %s", arg3); + } + + if (arg2[0]) + { + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_GAMETYPE\x14%s\x15 - \x14GAME_VOTE_MAP\x15%s", Game::Scr_GetGameTypeNameForScript(arg2), arg3); + } + else + { + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAP\x15%s", arg3); + } + } + else + { + sprintf_s(Game::level->voteString, "g_gametype %s; map_restart", arg2); + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_GAMETYPE\x14%s", Game::Scr_GetGameTypeNameForScript(arg2)); + } + + return true; + } + + bool Vote::HandleMap([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) + { + // This prevents abuse + if (!MapRotation::Contains("map", params->get(2))) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOTONROTATION\"", 0x65)); + return false; + } + + sprintf_s(Game::level->voteString, "%s %s", params->get(1), params->get(2)); + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAP\x15%s", params->get(2)); + return true; + } + + bool Vote::HandleGametype([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) + { + if (!Game::Scr_IsValidGameType(params->get(2))) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65)); + return false; + } + + sprintf_s(Game::level->voteString, "%s %s; map_restart", params->get(2), params->get(3)); + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_GAMETYPE\x14%s", Game::Scr_GetGameTypeNameForScript(params->get(2))); + return true; + } + + bool Vote::HandleKick(const Game::gentity_s* ent, const Command::ServerParams* params) + { + char cleanName[0x40]{}; + + auto kicknum = Game::level->maxclients; + for (auto i = 0; i < Game::level->maxclients; ++i) + { + if (Game::level->clients[i].sess.connected == Game::CON_CONNECTED) + { + strncpy_s(cleanName, Game::level->clients[i].sess.cs.name, _TRUNCATE); + Game::I_CleanStr(cleanName); + if (Utils::String::Compare(cleanName, params->get(2))) + { + kicknum = i; + } + } + } + + if (kicknum == Game::level->maxclients) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_CLIENTNOTONSERVER\"", 0x65)); + return false; + } + + sprintf_s(Game::level->voteString, "%s \"%d\"", "tempBanClient", kicknum); // kick and tempBanClient do the same thing + sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_KICK\x15(%i)%s", kicknum, Game::level->clients[kicknum].sess.cs.name); + return true; + } + + void Vote::Scr_VoteCalled(Game::gentity_s* self, const char* command, const char* param1, const char* param2) + { + Game::Scr_AddString(param2); + Game::Scr_AddString(param1); + Game::Scr_AddString(command); + Game::Scr_Notify(self, Game::scr_const->call_vote, 3); + } + + void Vote::Scr_PlayerVote(Game::gentity_s* self, const char* option) + { + Game::Scr_AddString(option); + Game::Scr_Notify(self, Game::scr_const->vote, 1); + } + + void Vote::Cmd_CallVote_f(Game::gentity_s* ent, const Command::ServerParams* params) + { + if (!(*Game::g_allowVote)->current.enabled) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTINGNOTENABLED\"", 0x65)); + return; + } + + if (Game::level->numConnectedClients < 2) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTINGNOTENOUGHPLAYERS\"", 0x65)); + return; + } + + if ((*Game::g_oldVoting)->current.enabled) + { + if (Game::level->voteTime) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTEALREADYINPROGRESS\"", 0x65)); + return; + } + + if (ent->client->sess.voteCount >= 3) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_MAXVOTESCALLED\"", 0x65)); + return; + } + + if (ent->client->sess.cs.team == Game::TEAM_SPECTATOR) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOSPECTATORCALLVOTE\"", 0x65)); + return; + } + } + + if (IsInvalidVoteString(params->get(1)) || + IsInvalidVoteString(params->get(2)) || + IsInvalidVoteString(params->get(3))) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDVOTESTRING\"", 0x65)); + return; + } + + if (!(*Game::g_oldVoting)->current.enabled) + { + Scr_VoteCalled(ent, params->get(1), params->get(2), params->get(3)); + return; + } + + const auto got = VoteCommands.find(params->get(1)); + if (got == VoteCommands.end()) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDVOTESTRING\"", 0x65)); + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA(CallVoteDesc, 0x65)); + return; + } + + if (Game::level->voteExecuteTime) + { + Game::level->voteExecuteTime = 0; + Game::Cbuf_AddText(0, VA("%s\n", Game::level->voteString)); + } + + const auto shouldDisplay = got->second(ent, params); + if (shouldDisplay) + { + DisplayVote(ent); + } + } + + void Vote::Cmd_Vote_f(Game::gentity_s* ent, const Command::ServerParams* params) + { + char arg1[0x100]{}; + + if ((*Game::g_oldVoting)->current.enabled) + { + if (!Game::level->voteTime) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOVOTEINPROGRESS\"", 0x65)); + return; + } + + if ((ent->client->ps.eFlags & Game::EF_VOTED) != 0) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTEALREADYCAST\"", 0x65)); + return; + } + + if (ent->client->sess.cs.team == Game::TEAM_SPECTATOR) + { + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOSPECTATORVOTE\"", 0x65)); + return; + } + + Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTECAST\"", 0x65)); + ent->client->ps.eFlags |= Game::EF_VOTED; + } + + strncpy_s(arg1, params->get(1), _TRUNCATE); + if (arg1[0] == 'y' || arg1[0] == 'Y' || arg1[0] == '1') + { + if ((*Game::g_oldVoting)->current.enabled) + { + Game::SV_SetConfigstring(Game::CS_VOTE_YES, VA("%i", ++Game::level->voteYes)); + } + else + { + Scr_PlayerVote(ent, "yes"); + } + } + else if ((*Game::g_oldVoting)->current.enabled) + { + Game::SV_SetConfigstring(Game::CS_VOTE_NO, VA("%i", ++Game::level->voteNo)); + } + else + { + Scr_PlayerVote(ent, "no"); + } + } + + Vote::Vote() + { + // Replicate g_allowVote + Utils::Hook::Set(0x5E3A4F, Game::DVAR_INTERNAL | Game::DVAR_CODINFO); + + ClientCommand::Add("callvote", Cmd_CallVote_f); + ClientCommand::Add("vote", Cmd_Vote_f); + + UIScript::Add("voteKick", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) + { + if (info->playerIndex >= 0 && info->playerIndex < Game::sharedUiInfo->playerCount) + { + Game::Cbuf_AddText(0, VA("callvote kick \"%s\"\n", Game::sharedUiInfo->playerNames[info->playerIndex])); + } + }); + + UIScript::Add("voteTempBan", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) + { + if (info->playerIndex >= 0 && info->playerIndex < Game::sharedUiInfo->playerCount) + { + Game::Cbuf_AddText(0, VA("callvote tempBanUser \"%s\"\n", Game::sharedUiInfo->playerNames[info->playerIndex])); + } + }); + + UIScript::Add("voteTypeMap", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) + { + Game::Cbuf_AddText(0, VA("callvote typemap %s %s\n", Game::sharedUiInfo->gameTypes[(*Game::ui_netGameType)->current.integer].gameType, + Game::sharedUiInfo->mapList[(*Game::ui_currentMap)->current.integer].mapName)); + }); + + UIScript::Add("voteMap", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) + { + if ((*Game::ui_currentMap)->current.integer >= 0 && + (*Game::ui_currentMap)->current.integer < Game::sharedUiInfo->mapCount) + { + Game::Cbuf_AddText(0, VA("callvote map %s\n", Game::sharedUiInfo->mapList[(*Game::ui_currentMap)->current.integer].mapName)); + } + }); + + UIScript::Add("voteGame", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) + { + Game::Cbuf_AddText(0, VA("callvote g_gametype %s\n", Game::sharedUiInfo->gameTypes[(*Game::ui_netGameType)->current.integer].gameType)); + }); + } +} diff --git a/src/Components/Modules/Vote.hpp b/src/Components/Modules/Vote.hpp new file mode 100644 index 00000000..82b35d22 --- /dev/null +++ b/src/Components/Modules/Vote.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace Components +{ + class Vote : public Component + { + public: + Vote(); + + private: + using CommandHandler = std::function; + static std::unordered_map VoteCommands; + + static constexpr auto* CallVoteDesc = "%c \"GAME_VOTECOMMANDSARE\x15 map_restart, map_rotate, map , g_gametype , typemap , " + "kick , tempBanUser \""; + + static void DisplayVote(const Game::gentity_s* ent); + static bool IsInvalidVoteString(const std::string& input); + + static bool HandleMapRestart(const Game::gentity_s* ent, const Command::ServerParams* params); + static bool HandleMapRotate(const Game::gentity_s* ent, const Command::ServerParams* params); + static bool HandleTypemap(const Game::gentity_s* ent, const Command::ServerParams* params); + static bool HandleMap(const Game::gentity_s* ent, const Command::ServerParams* params); + static bool HandleGametype(const Game::gentity_s* ent, const Command::ServerParams* params); + static bool HandleKick(const Game::gentity_s* ent, const Command::ServerParams* params); + + static void Scr_VoteCalled(Game::gentity_s* self, const char* command, const char* param1, const char* param2); + static void Scr_PlayerVote(Game::gentity_s* self, const char* option); + + static void Cmd_CallVote_f(Game::gentity_s* ent, const Command::ServerParams* params); + static void Cmd_Vote_f(Game::gentity_s* ent, const Command::ServerParams* params); + }; +} diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index 3bc00b25..d3d6a373 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -1523,7 +1523,7 @@ namespace Components } Logger::Print("------------------- BEGIN IWI DUMP -------------------\n"); - Logger::Print("{}\n", json11::Json(images).dump()); + Logger::Print("{}\n", nlohmann::json(images).dump()); Logger::Print("------------------- END IWI DUMP -------------------\n"); }); diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index edcada03..e59c73cd 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -3483,14 +3483,14 @@ namespace Components Command::Add("decryptImages", [](Command::Params*) { - auto images = Game::Sys_ListFilesWrapper("iw4x/images", "iwi"); + auto images = FileSystem::GetSysFileList("iw4x/images", "iwi"); Logger::Print("decrypting {} images...\n", images.size()); for (auto& image : images) { char* buffer = nullptr; auto fileLength = Game::FS_ReadFile(Utils::String::VA("images/%s", image.data()), &buffer); - + if (fileLength && buffer) { if (!std::filesystem::exists("raw/images")) @@ -3514,9 +3514,10 @@ namespace Components Logger::Print("decrypted {} images!\n", images.size()); }); + Command::Add("decryptSounds", [](Command::Params*) { - auto sounds = Game::Sys_ListFilesWrapper("iw4x/sound", "iwi"); + auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi"); Logger::Print("decrypting {} sounds...\n", sounds.size()); for (auto& sound : sounds) diff --git a/src/DllMain.cpp b/src/DllMain.cpp index 53cf58b5..5860b701 100644 --- a/src/DllMain.cpp +++ b/src/DllMain.cpp @@ -11,7 +11,7 @@ namespace Main #if defined(DEBUG) || defined(FORCE_UNIT_TESTS) if (Components::Loader::IsPerformingUnitTests()) { - DWORD result = (Components::Loader::PerformUnitTests() ? 0 : -1); + auto result = (Components::Loader::PerformUnitTests() ? 0 : -1); Components::Loader::Uninitialize(); ExitProcess(result); } @@ -26,7 +26,6 @@ namespace Main void Uninitialize() { Components::Loader::Uninitialize(); - Utils::Cache::Uninitialize(); google::protobuf::ShutdownProtobufLibrary(); } @@ -45,13 +44,11 @@ namespace Main } } -BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) +BOOL APIENTRY DllMain(HINSTANCE /*hinstDLL*/, DWORD fdwReason, LPVOID /*lpvReserved*/) { - if (ul_reason_for_call == DLL_PROCESS_ATTACH) + if (fdwReason == DLL_PROCESS_ATTACH) { - // Not sure if it conflicts with our TLS variables - //DisableThreadLibraryCalls(hModule); - + SetProcessDEPPolicy(PROCESS_DEP_ENABLE); Steam::Proxy::RunMod(); #ifndef DISABLE_BINARY_CHECK @@ -75,7 +72,7 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l // Install entry point hook Utils::Hook(0x6BAC0F, Main::EntryPoint, HOOK_JUMP).install()->quick(); } - else if (ul_reason_for_call == DLL_PROCESS_DETACH) + else if (fdwReason == DLL_PROCESS_DETACH) { Main::Uninitialize(); } diff --git a/src/Game/BothGames.cpp b/src/Game/BothGames.cpp new file mode 100644 index 00000000..723645e9 --- /dev/null +++ b/src/Game/BothGames.cpp @@ -0,0 +1,11 @@ +#include + +namespace Game +{ + BG_GetNumWeapons_t BG_GetNumWeapons = BG_GetNumWeapons_t(0x4F5CC0); + BG_GetWeaponName_t BG_GetWeaponName = BG_GetWeaponName_t(0x4E6EC0); + BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = BG_LoadWeaponDef_LoadObj_t(0x57B5F0); + BG_LoadWeaponCompleteDefInternal_t BG_LoadWeaponCompleteDefInternal = BG_LoadWeaponCompleteDefInternal_t(0x4B5F10); + BG_GetWeaponDef_t BG_GetWeaponDef = BG_GetWeaponDef_t(0x440EB0); + BG_GetEntityTypeName_t BG_GetEntityTypeName = BG_GetEntityTypeName_t(0x43A0E0); +} diff --git a/src/Game/BothGames.hpp b/src/Game/BothGames.hpp new file mode 100644 index 00000000..3f65a63b --- /dev/null +++ b/src/Game/BothGames.hpp @@ -0,0 +1,22 @@ +#pragma once + +namespace Game +{ + typedef unsigned int(*BG_GetNumWeapons_t)(); + extern BG_GetNumWeapons_t BG_GetNumWeapons; + + typedef const char*(*BG_GetWeaponName_t)(unsigned int index); + extern BG_GetWeaponName_t BG_GetWeaponName; + + typedef void*(*BG_LoadWeaponDef_LoadObj_t)(const char* name); + extern BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj; + + typedef WeaponCompleteDef*(*BG_LoadWeaponCompleteDefInternal_t)(const char* folder, const char* name); + extern BG_LoadWeaponCompleteDefInternal_t BG_LoadWeaponCompleteDefInternal; + + typedef WeaponDef*(*BG_GetWeaponDef_t)(unsigned int weaponIndex); + extern BG_GetWeaponDef_t BG_GetWeaponDef; + + typedef const char*(*BG_GetEntityTypeName_t)(int eType); + extern BG_GetEntityTypeName_t BG_GetEntityTypeName; +} diff --git a/src/Game/Client.cpp b/src/Game/Client.cpp new file mode 100644 index 00000000..4798a21c --- /dev/null +++ b/src/Game/Client.cpp @@ -0,0 +1,61 @@ +#include + +namespace Game +{ + CL_GetClientName_t CL_GetClientName = CL_GetClientName_t(0x4563D0); + CL_IsCgameInitialized_t CL_IsCgameInitialized = CL_IsCgameInitialized_t(0x43EB20); + CL_ConnectFromParty_t CL_ConnectFromParty = CL_ConnectFromParty_t(0x433D30); + CL_DownloadsComplete_t CL_DownloadsComplete = CL_DownloadsComplete_t(0x42CE90); + CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical = CL_DrawStretchPicPhysical_t(0x4FC120); + CL_GetConfigString_t CL_GetConfigString = CL_GetConfigString_t(0x44ADB0); + CL_GetMaxRank_t CL_GetMaxRank = CL_GetMaxRank_t(0x44BA30); + CL_GetRankForXP_t CL_GetRankForXP = CL_GetRankForXP_t(0x4FF8A0); + CL_GetRankIcon_t CL_GetRankIcon = CL_GetRankIcon_t(0x4A7B30); + CL_HandleRelayPacket_t CL_HandleRelayPacket = CL_HandleRelayPacket_t(0x5A8C70); + CL_ResetViewport_t CL_ResetViewport = CL_ResetViewport_t(0x4A8830); + CL_SelectStringTableEntryInDvar_f_t CL_SelectStringTableEntryInDvar_f = CL_SelectStringTableEntryInDvar_f_t(0x4A4560); + CL_DrawStretchPic_t CL_DrawStretchPic = CL_DrawStretchPic_t(0x412490); + CL_ConsoleFixPosition_t CL_ConsoleFixPosition = CL_ConsoleFixPosition_t(0x44A430); + CL_GetLocalClientActiveCount_t CL_GetLocalClientActiveCount = CL_GetLocalClientActiveCount_t(0x5BAD90); + CL_ControllerIndexFromClientNum_t CL_ControllerIndexFromClientNum = CL_ControllerIndexFromClientNum_t(0x449E30); + CL_MouseEvent_t CL_MouseEvent = CL_MouseEvent_t(0x4D7C50); + + float* cl_angles = reinterpret_cast(0xB2F8D0); + + clientConnection_t* clientConnections = reinterpret_cast(0xA1E878); + + clientStatic_t* cls = reinterpret_cast(0xA7FE90); + + clientUIActive_t* clientUIActives = reinterpret_cast(0xB2BB88); + + voiceCommunication_t* cl_voiceCommunication = reinterpret_cast(0x1079DA0); + + int CL_GetMaxXP() + { + StringTable* rankTable = DB_FindXAssetHeader(ASSET_TYPE_STRINGTABLE, "mp/rankTable.csv").stringTable; + const char* maxrank = StringTable_Lookup(rankTable, 0, "maxrank", 1); + return atoi(StringTable_Lookup(rankTable, 0, maxrank, 7)); + } + + clientConnection_t* CL_GetLocalClientConnection(const int localClientNum) + { + assert(clientConnections); + AssertIn(localClientNum, MAX_LOCAL_CLIENTS); + + return &clientConnections[localClientNum]; + } + + connstate_t CL_GetLocalClientConnectionState(const int localClientNum) + { + AssertIn(localClientNum, STATIC_MAX_LOCAL_CLIENTS); + + return clientUIActives[localClientNum].connectionState; + } + + voiceCommunication_t* CL_GetLocalClientVoiceCommunication([[maybe_unused]] const int localClientNum) + { + AssertIn(localClientNum, STATIC_MAX_LOCAL_CLIENTS); + + return cl_voiceCommunication; + } +} diff --git a/src/Game/Client.hpp b/src/Game/Client.hpp new file mode 100644 index 00000000..834d73fa --- /dev/null +++ b/src/Game/Client.hpp @@ -0,0 +1,70 @@ +#pragma once + +namespace Game +{ + typedef int(*CL_GetClientName_t)(int localClientNum, int index, char* buf, int size); + extern CL_GetClientName_t CL_GetClientName; + + typedef int(*CL_IsCgameInitialized_t)(); + extern CL_IsCgameInitialized_t CL_IsCgameInitialized; + + typedef void(*CL_ConnectFromParty_t)(int controllerIndex, _XSESSION_INFO* hostInfo, netadr_t addr, int numPublicSlots, int numPrivateSlots, const char* mapname, const char* gametype); + extern CL_ConnectFromParty_t CL_ConnectFromParty; + + typedef void(*CL_DownloadsComplete_t)(int controller); + extern CL_DownloadsComplete_t CL_DownloadsComplete; + + typedef void(*CL_DrawStretchPicPhysical_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float* color, Material* material); + extern CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical; + + typedef const char* (*CL_GetConfigString_t)(int index); + extern CL_GetConfigString_t CL_GetConfigString; + + typedef int(*CL_GetMaxRank_t)(); + extern CL_GetMaxRank_t CL_GetMaxRank; + + typedef int(*CL_GetRankForXP_t)(int xp); + extern CL_GetRankForXP_t CL_GetRankForXP; + + typedef void(*CL_GetRankIcon_t)(int level, int prestige, Material** material); + extern CL_GetRankIcon_t CL_GetRankIcon; + + typedef void(*CL_HandleRelayPacket_t)(Game::msg_t* msg, int client); + extern CL_HandleRelayPacket_t CL_HandleRelayPacket; + + typedef void(*CL_ResetViewport_t)(); + extern CL_ResetViewport_t CL_ResetViewport; + + typedef void(*CL_SelectStringTableEntryInDvar_f_t)(); + extern CL_SelectStringTableEntryInDvar_f_t CL_SelectStringTableEntryInDvar_f; + + typedef void(*CL_DrawStretchPic_t)(const ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, float s1, float t1, float s2, float t2, const float* color, Material* material); + extern CL_DrawStretchPic_t CL_DrawStretchPic; + + typedef void(*CL_ConsoleFixPosition_t)(); + extern CL_ConsoleFixPosition_t CL_ConsoleFixPosition; + + typedef int(*CL_GetLocalClientActiveCount_t)(); + extern CL_GetLocalClientActiveCount_t CL_GetLocalClientActiveCount; + + typedef int(*CL_ControllerIndexFromClientNum_t)(int localActiveClientNum); + extern CL_ControllerIndexFromClientNum_t CL_ControllerIndexFromClientNum; + + typedef int(*CL_MouseEvent_t)(int x, int y, int dx, int dy); + extern CL_MouseEvent_t CL_MouseEvent; + + extern float* cl_angles; + + extern clientConnection_t* clientConnections; + + extern clientStatic_t* cls; + + extern clientUIActive_t* clientUIActives; + + extern voiceCommunication_t* cl_voiceCommunication; + + extern int CL_GetMaxXP(); + extern clientConnection_t* CL_GetLocalClientConnection(int localClientNum); + extern connstate_t CL_GetLocalClientConnectionState(int localClientNum); + extern voiceCommunication_t* CL_GetLocalClientVoiceCommunication(int localClientNum); +} diff --git a/src/Game/Database.cpp b/src/Game/Database.cpp new file mode 100644 index 00000000..71e2926b --- /dev/null +++ b/src/Game/Database.cpp @@ -0,0 +1,183 @@ +#include + +namespace Game +{ + DB_BeginRecoverLostDevice_t DB_BeginRecoverLostDevice = DB_BeginRecoverLostDevice_t(0x4BFF90); + DB_EndRecoverLostDevice_t DB_EndRecoverLostDevice = DB_EndRecoverLostDevice_t(0x46B660); + DB_EnumXAssets_t DB_EnumXAssets = DB_EnumXAssets_t(0x4B76D0); + DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal = DB_EnumXAssets_Internal_t(0x5BB0A0); + DB_FindXAssetHeader_t DB_FindXAssetHeader = DB_FindXAssetHeader_t(0x407930); + DB_GetRawBuffer_t DB_GetRawBuffer = DB_GetRawBuffer_t(0x4CDC50); + DB_GetRawFileLen_t DB_GetRawFileLen = DB_GetRawFileLen_t(0x4DAA80); + DB_GetLoadedFraction_t DB_GetLoadedFraction = DB_GetLoadedFraction_t(0x468380); + DB_GetXAssetTypeName_t DB_GetXAssetTypeName = DB_GetXAssetTypeName_t(0x4CFCF0); + DB_IsXAssetDefault_t DB_IsXAssetDefault = DB_IsXAssetDefault_t(0x48E6A0); + DB_LoadXAssets_t DB_LoadXAssets = DB_LoadXAssets_t(0x4E5930); + DB_LoadXFileData_t DB_LoadXFileData = DB_LoadXFileData_t(0x445460); + DB_ReadXFile_t DB_ReadXFile = DB_ReadXFile_t(0x445460); + DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed = DB_ReadXFileUncompressed_t(0x4705E0); + DB_SetXAssetName_t DB_SetXAssetName = DB_SetXAssetName_t(0x453580); + DB_XModelSurfsFixup_t DB_XModelSurfsFixup = DB_XModelSurfsFixup_t(0x5BAC50); + + DB_SetXAssetNameHandler_t* DB_SetXAssetNameHandlers = reinterpret_cast(0x7993D8); + DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = reinterpret_cast(0x799328); + DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = reinterpret_cast(0x799488); + DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers = reinterpret_cast(0x799AB8); + + XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); + unsigned int* g_poolSize = reinterpret_cast(0x7995E8); + + XBlock** g_streamBlocks = reinterpret_cast(0x16E554C); + int* g_streamPos = reinterpret_cast(0x16E5554); + int* g_streamPosIndex = reinterpret_cast(0x16E5578); + + FastCriticalSection* db_hashCritSect = reinterpret_cast(0x16B8A54); + + XZone* g_zones = reinterpret_cast(0x14C0F80); + unsigned short* db_hashTable = reinterpret_cast(0x12412B0); + + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize) + { + const auto size = DB_GetXAssetSizeHandlers[type](); + XAssetHeader poolEntry = {Utils::Memory::GetAllocator()->allocate(newSize * size)}; + DB_XAssetPool[type] = poolEntry; + g_poolSize[type] = newSize; + return poolEntry; + } + + const char* DB_GetXAssetName(XAsset* asset) + { + if (!asset) return ""; + return DB_GetXAssetNameHandlers[asset->type](&asset->header); + } + + XAssetType DB_GetXAssetNameType(const char* name) + { + for (int i = 0; i < ASSET_TYPE_COUNT; ++i) + { + XAssetType type = static_cast(i); + if (!_stricmp(DB_GetXAssetTypeName(type), name)) + { + // Col map workaround! + if (type == Game::ASSET_TYPE_CLIPMAP_SP) + { + return Game::ASSET_TYPE_CLIPMAP_MP; + } + + return type; + } + } + + return ASSET_TYPE_INVALID; + } + + int DB_GetZoneIndex(const std::string& name) + { + for (int i = 0; i < 32; ++i) + { + if (Game::g_zones[i].name == name) + { + return i; + } + } + + return -1; + } + + bool DB_IsZoneLoaded(const char* zone) + { + auto zoneCount = Utils::Hook::Get(0x1261BCC); + auto* zoneIndices = reinterpret_cast(0x16B8A34); + auto* zoneData = reinterpret_cast(0x14C0F80); + + for (int i = 0; i < zoneCount; ++i) + { + std::string name = zoneData + 4 + 0xA4 * (zoneIndices[i] & 0xFF); + + if (name == zone) + { + return true; + } + } + + return false; + } + + void DB_EnumXAssetEntries(XAssetType type, std::function callback, bool overrides) + { + Sys_LockRead(db_hashCritSect); + + const auto pool = Components::Maps::GetAssetEntryPool(); + for (auto hash = 0; hash < 37000; hash++) + { + auto hashIndex = db_hashTable[hash]; + while (hashIndex) + { + auto* assetEntry = &pool[hashIndex]; + + if (assetEntry->asset.type == type) + { + callback(assetEntry); + if (overrides) + { + auto overrideIndex = assetEntry->nextOverride; + while (overrideIndex) + { + auto* overrideEntry = &pool[overrideIndex]; + callback(overrideEntry); + overrideIndex = overrideEntry->nextOverride; + } + } + } + + hashIndex = assetEntry->nextHash; + } + } + + Sys_UnlockRead(db_hashCritSect); + } + + __declspec(naked) XAssetHeader DB_FindXAssetDefaultHeaderInternal(XAssetType /*type*/) + { + __asm + { + push eax + pushad + + mov eax, 5BB210h + mov edi, [esp + 28h] + call eax + + mov [esp + 20h], eax + popad + pop eax + + retn + } + } + + __declspec(naked) XAssetEntry* DB_FindXAssetEntry(XAssetType /*type*/, const char* /*name*/) + { + __asm + { + push eax + pushad + + mov edi, [esp + 2Ch] // name + push edi + + mov edi, [esp + 2Ch] // type + + mov eax, 5BB1B0h + call eax + + add esp, 4h + + mov [esp + 20h], eax + popad + pop eax + + retn + } + } +} diff --git a/src/Game/Database.hpp b/src/Game/Database.hpp new file mode 100644 index 00000000..fc830e2f --- /dev/null +++ b/src/Game/Database.hpp @@ -0,0 +1,114 @@ +#pragma once + +namespace Game +{ + template static void DB_ConvertOffsetToPointer(T* pointer) + { + Utils::Hook::Call(0x4A82B0)(pointer); + } + + template static T** DB_InsertPointer() + { + static auto DB_InsertPointer_t = 0x43B290; + T** result = nullptr; + + __asm + { + call DB_InsertPointer_t; + mov result, eax; + } + + return result; + } + + typedef char*(*DB_AllocStreamPos_t)(int alignment); + extern DB_AllocStreamPos_t DB_AllocStreamPos; + + typedef void(*DB_PushStreamPos_t)(unsigned int index); + extern DB_PushStreamPos_t DB_PushStreamPos; + + typedef void(*DB_PopStreamPos_t)(); + extern DB_PopStreamPos_t DB_PopStreamPos; + + typedef void(*DB_BeginRecoverLostDevice_t)(); + extern DB_BeginRecoverLostDevice_t DB_BeginRecoverLostDevice; + + typedef void(*DB_EndRecoverLostDevice_t)(); + extern DB_EndRecoverLostDevice_t DB_EndRecoverLostDevice; + + typedef void(*DB_EnumXAssets_t)(XAssetType type, void(*)(XAssetHeader, void*), void* userdata, bool overrides); + extern DB_EnumXAssets_t DB_EnumXAssets; + + typedef void(*DB_EnumXAssets_Internal_t)(XAssetType type, void(*)(XAssetHeader, void*), void* userdata, bool overrides); + extern DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal; + + typedef XAssetHeader(*DB_FindXAssetHeader_t)(XAssetType type, const char* name); + extern DB_FindXAssetHeader_t DB_FindXAssetHeader; + + typedef float(*DB_GetLoadedFraction_t)(); + extern DB_GetLoadedFraction_t DB_GetLoadedFraction; + + typedef const char*(*DB_GetXAssetTypeName_t)(XAssetType type); + extern DB_GetXAssetTypeName_t DB_GetXAssetTypeName; + + typedef int(*DB_IsXAssetDefault_t)(XAssetType type, const char* name); + extern DB_IsXAssetDefault_t DB_IsXAssetDefault; + + typedef void(*DB_GetRawBuffer_t)(RawFile* rawfile, char* buffer, int size); + extern DB_GetRawBuffer_t DB_GetRawBuffer; + + typedef int(*DB_GetRawFileLen_t)(RawFile* rawfile); + extern DB_GetRawFileLen_t DB_GetRawFileLen; + + typedef void(*DB_LoadXAssets_t)(XZoneInfo* zoneInfo, unsigned int zoneCount, int sync); + extern DB_LoadXAssets_t DB_LoadXAssets; + + typedef void(*DB_LoadXFileData_t)(char* pos, int size); + extern DB_LoadXFileData_t DB_LoadXFileData; + + typedef void(*DB_ReadXFileUncompressed_t)(void* buffer, int size); + extern DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed; + + typedef void(*DB_ReadXFile_t)(void* buffer, int size); + extern DB_ReadXFile_t DB_ReadXFile; + + typedef void(*DB_SetXAssetName_t)(XAsset* asset, const char* name); + extern DB_SetXAssetName_t DB_SetXAssetName; + + typedef void(*DB_XModelSurfsFixup_t)(XModel* model); + extern DB_XModelSurfsFixup_t DB_XModelSurfsFixup; + + typedef void(*DB_SetXAssetNameHandler_t)(XAssetHeader* header, const char* name); + extern DB_SetXAssetNameHandler_t* DB_SetXAssetNameHandlers; + + typedef int(*DB_GetXAssetSizeHandler_t)(); + extern DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers; + + typedef const char* (*DB_GetXAssetNameHandler_t)(XAssetHeader* asset); + extern DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers; + + typedef void(*DB_ReleaseXAssetHandler_t)(XAssetHeader header); + extern DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers; + + extern XAssetHeader* DB_XAssetPool; + extern unsigned int* g_poolSize; + + extern XBlock** g_streamBlocks; + extern int* g_streamPos; + extern int* g_streamPosIndex; + + extern FastCriticalSection* db_hashCritSect; + + extern XZone* g_zones; + extern unsigned short* db_hashTable; + + extern XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize); + + extern const char* DB_GetXAssetName(XAsset* asset); + extern XAssetType DB_GetXAssetNameType(const char* name); + extern int DB_GetZoneIndex(const std::string& name); + extern bool DB_IsZoneLoaded(const char* zone); + extern void DB_EnumXAssetEntries(XAssetType type, std::function callback, bool overrides); + extern XAssetHeader DB_FindXAssetDefaultHeaderInternal(XAssetType type); + extern XAssetEntry* DB_FindXAssetEntry(XAssetType type, const char* name); +} diff --git a/src/Game/Dvars.cpp b/src/Game/Dvars.cpp new file mode 100644 index 00000000..3e3fde5b --- /dev/null +++ b/src/Game/Dvars.cpp @@ -0,0 +1,106 @@ +#include + +namespace Game +{ + Dvar_RegisterBool_t Dvar_RegisterBool = Dvar_RegisterBool_t(0x4CE1A0); + Dvar_RegisterFloat_t Dvar_RegisterFloat = Dvar_RegisterFloat_t(0x648440); + Dvar_RegisterVec2_t Dvar_RegisterVec2 = Dvar_RegisterVec2_t(0x4F6070); + Dvar_RegisterVec3_t Dvar_RegisterVec3 = Dvar_RegisterVec3_t(0x4EF8E0); + Dvar_RegisterVec4_t Dvar_RegisterVec4 = Dvar_RegisterVec4_t(0x471500); + Dvar_RegisterInt_t Dvar_RegisterInt = Dvar_RegisterInt_t(0x479830); + Dvar_RegisterEnum_t Dvar_RegisterEnum = Dvar_RegisterEnum_t(0x412E40); + Dvar_RegisterString_t Dvar_RegisterString = Dvar_RegisterString_t(0x4FC7E0); + Dvar_RegisterColor_t Dvar_RegisterColor = Dvar_RegisterColor_t(0x4F28E0); + Dvar_RegisterVec3Color_t Dvar_RegisterVec3Color = Dvar_RegisterVec3Color_t(0x4918B0); + + Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName = Dvar_GetUnpackedColorByName_t(0x406530); + Dvar_GetString_t Dvar_GetString = Dvar_GetString_t(0x4EC6B0); + Dvar_GetVariantString_t Dvar_GetVariantString = Dvar_GetVariantString_t(0x4C47E0); + Dvar_FindVar_t Dvar_FindVar = Dvar_FindVar_t(0x4D5390); + Dvar_InfoString_Big_t Dvar_InfoString_Big = Dvar_InfoString_Big_t(0x4D98A0); + Dvar_SetCommand_t Dvar_SetCommand = Dvar_SetCommand_t(0x4EE430); + Dvar_DisplayableValue_t Dvar_DisplayableValue = Dvar_DisplayableValue_t(0x4B5530); + Dvar_Reset_t Dvar_Reset = Dvar_Reset_t(0x4FEFD0); + + const dvar_t** com_developer = reinterpret_cast(0x1AD78E8); + const dvar_t** com_developer_script = reinterpret_cast(0x1AD8F10); + const dvar_t** com_timescale = reinterpret_cast(0x1AD7920); + const dvar_t** com_sv_running = reinterpret_cast(0x1AD7934); + + const dvar_t** dev_timescale = reinterpret_cast(0x1AD8F20); + + const dvar_t** dvar_cheats = reinterpret_cast(0x63F3348); + + const dvar_t** fs_gameDirVar = reinterpret_cast(0x63D0CC0); + + const dvar_t** sv_hostname = reinterpret_cast(0x2098D98); + const dvar_t** sv_gametype = reinterpret_cast(0x2098DD4); + const dvar_t** sv_mapname = reinterpret_cast(0x2098DDC); + const dvar_t** sv_mapRotation = reinterpret_cast(0x62C7C44); + const dvar_t** sv_mapRotationCurrent = reinterpret_cast(0x2098DF0); + const dvar_t** sv_maxclients = reinterpret_cast(0x2098D90); + const dvar_t** sv_cheats = reinterpret_cast(0x2098DE0); + const dvar_t** sv_voiceQuality = reinterpret_cast(0x2098DB0); + + const dvar_t** cl_showSend = reinterpret_cast(0xA1E870); + const dvar_t** cl_voice = reinterpret_cast(0xB2BB44); + const dvar_t** cl_ingame = reinterpret_cast(0xB2BB80); + + const dvar_t** g_cheats = reinterpret_cast(0x1A45D54); + const dvar_t** g_deadChat = reinterpret_cast(0x19BD5DC); + const dvar_t** g_allowVote = reinterpret_cast(0x19BD644); + const dvar_t** g_oldVoting = reinterpret_cast(0x1A45DEC); + const dvar_t** g_gametype = reinterpret_cast(0x1A45DC8); + + const dvar_t** version = reinterpret_cast(0x1AD7930); + + const dvar_t** viewposNow = reinterpret_cast(0x9FD30C); + + const dvar_t** ui_currentMap = reinterpret_cast(0x62E2834); + const dvar_t** ui_gametype = reinterpret_cast(0x62E2828); + const dvar_t** ui_mapname = reinterpret_cast(0x62E279C); + const dvar_t** ui_netGameType = reinterpret_cast(0x62E2838); + + const dvar_t** loc_warnings = reinterpret_cast(0x62C8700); + const dvar_t** loc_warningsAsErrors = reinterpret_cast(0x62C86FC); + + __declspec(naked) void Dvar_SetVariant(dvar_t*, DvarValue, DvarSetSource) + { + static DWORD Dvar_SetVariant_t = 0x647400; + + __asm + { + pushad + + mov eax, [esp + 0x4 + 0x20] // dvar + push [esp + 0x18 + 0x20] // source + push [esp + 0x18 + 0x20] // value + push [esp + 0x18 + 0x20] // value + push [esp + 0x18 + 0x20] // value + push [esp + 0x18 + 0x20] // value + + call Dvar_SetVariant_t + add esp, 0x14 + + popad + + retn + } + } + + void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source) + { + static DWORD Dvar_SetFromStringFromSource_t = 0x648580; + + __asm + { + pushad + mov esi, dvar + mov eax, string + push source + call Dvar_SetFromStringFromSource_t + add esp, 0x4 + popad + } + } +} diff --git a/src/Game/Dvars.hpp b/src/Game/Dvars.hpp new file mode 100644 index 00000000..61697af7 --- /dev/null +++ b/src/Game/Dvars.hpp @@ -0,0 +1,125 @@ +#pragma once + +// Put game dvars here +namespace Game +{ + typedef dvar_t*(*Dvar_RegisterBool_t)(const char* dvarName, bool value, unsigned __int16 flags, const char* description); + extern Dvar_RegisterBool_t Dvar_RegisterBool; + + typedef dvar_t*(*Dvar_RegisterFloat_t)(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description); + extern Dvar_RegisterFloat_t Dvar_RegisterFloat; + + typedef dvar_t*(*Dvar_RegisterVec2_t)(const char* dvarName, float x, float y, float min, float max, unsigned __int16 flags, const char* description); + extern Dvar_RegisterVec2_t Dvar_RegisterVec2; + + typedef dvar_t*(*Dvar_RegisterVec3_t)(const char* dvarName, float x, float y, float z, float min, float max, unsigned __int16 flags, const char* description); + extern Dvar_RegisterVec3_t Dvar_RegisterVec3; + + typedef dvar_t*(*Dvar_RegisterVec4_t)(const char* dvarName, float x, float y, float z, float w, float min, float max, unsigned __int16 flags, const char* description); + extern Dvar_RegisterVec4_t Dvar_RegisterVec4; + + typedef dvar_t*(*Dvar_RegisterInt_t)(const char* dvarName, int value, int min, int max, unsigned __int16 flags, const char* description); + extern Dvar_RegisterInt_t Dvar_RegisterInt; + + typedef dvar_t*(*Dvar_RegisterEnum_t)(const char* dvarName, const char** valueList, int defaultIndex, unsigned __int16 flags, const char* description); + extern Dvar_RegisterEnum_t Dvar_RegisterEnum; + + typedef dvar_t*(*Dvar_RegisterString_t)(const char* dvarName, const char* value, unsigned __int16 flags, const char* description); + extern Dvar_RegisterString_t Dvar_RegisterString; + + typedef dvar_t*(*Dvar_RegisterColor_t)(const char* dvarName, float r, float g, float b, float a, unsigned __int16 flags, const char* description); + extern Dvar_RegisterColor_t Dvar_RegisterColor; + + typedef dvar_t*(*Dvar_RegisterVec3Color_t)(const char* dvarName, float x, float y, float z, float max, unsigned __int16 flags, const char* description); + extern Dvar_RegisterVec3Color_t Dvar_RegisterVec3Color; + + typedef void(*Dvar_SetFromStringByName_t)(const char* dvarName, const char* string); + extern Dvar_SetFromStringByName_t Dvar_SetFromStringByName; + + typedef const dvar_t*(*Dvar_SetFromStringByNameFromSource_t)(const char* dvarName, const char* string, DvarSetSource source); + extern Dvar_SetFromStringByNameFromSource_t Dvar_SetFromStringByNameFromSource; + + typedef void(*Dvar_SetStringByName_t)(const char* dvarName, const char* value); + extern Dvar_SetStringByName_t Dvar_SetStringByName; + + typedef void(*Dvar_SetString_t)(const dvar_t* dvar, const char* value); + extern Dvar_SetString_t Dvar_SetString; + + typedef void(*Dvar_SetBool_t)(const dvar_t* dvar, bool enabled); + extern Dvar_SetBool_t Dvar_SetBool; + + typedef void(*Dvar_SetFloat_t)(const dvar_t* dvar, float value); + extern Dvar_SetFloat_t Dvar_SetFloat; + + typedef void(*Dvar_SetInt_t)(const dvar_t* dvar, int integer); + extern Dvar_SetInt_t Dvar_SetInt; + + typedef void(*Dvar_GetUnpackedColorByName_t)(const char* dvarName, float* expandedColor); + extern Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName; + + typedef char*(*Dvar_GetString_t)(const char* dvarName); + extern Dvar_GetString_t Dvar_GetString; + + typedef char*(*Dvar_GetVariantString_t)(const char* dvarName); + extern Dvar_GetVariantString_t Dvar_GetVariantString; + + typedef dvar_t*(*Dvar_FindVar_t)(const char* dvarName); + extern Dvar_FindVar_t Dvar_FindVar; + + typedef char*(*Dvar_InfoString_Big_t)(int bit); + extern Dvar_InfoString_Big_t Dvar_InfoString_Big; + + typedef void(*Dvar_SetCommand_t)(const char* dvarName, const char* string); + extern Dvar_SetCommand_t Dvar_SetCommand; + + typedef const char*(*Dvar_DisplayableValue_t)(const dvar_t* dvar); + extern Dvar_DisplayableValue_t Dvar_DisplayableValue; + + typedef void(*Dvar_Reset_t)(const dvar_t* dvar, DvarSetSource setSource); + extern Dvar_Reset_t Dvar_Reset; + + extern const dvar_t** com_developer; + extern const dvar_t** com_developer_script; + extern const dvar_t** com_timescale; + extern const dvar_t** com_sv_running; + + extern const dvar_t** dev_timescale; + + extern const dvar_t** dvar_cheats; + + extern const dvar_t** fs_gameDirVar; + + extern const dvar_t** sv_hostname; + extern const dvar_t** sv_gametype; + extern const dvar_t** sv_mapname; + extern const dvar_t** sv_mapRotation; + extern const dvar_t** sv_mapRotationCurrent; + extern const dvar_t** sv_maxclients; + extern const dvar_t** sv_cheats; + extern const dvar_t** sv_voiceQuality; + + extern const dvar_t** cl_showSend; + extern const dvar_t** cl_voice; + extern const dvar_t** cl_ingame; + + extern const dvar_t** g_cheats; + extern const dvar_t** g_deadChat; + extern const dvar_t** g_allowVote; + extern const dvar_t** g_oldVoting; + extern const dvar_t** g_gametype; + + extern const dvar_t** version; + + extern const dvar_t** viewposNow; + + extern const dvar_t** ui_currentMap; + extern const dvar_t** ui_gametype; + extern const dvar_t** ui_mapname; + extern const dvar_t** ui_netGameType; + + extern const dvar_t** loc_warnings; + extern const dvar_t** loc_warningsAsErrors; + + extern void Dvar_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source); + extern void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source); +} diff --git a/src/Game/Engine/LargeLocal.cpp b/src/Game/Engine/LargeLocal.cpp new file mode 100644 index 00000000..638584c5 --- /dev/null +++ b/src/Game/Engine/LargeLocal.cpp @@ -0,0 +1,92 @@ +#include +#include "LargeLocal.hpp" + +namespace Game::Engine +{ + #define CanUseServerLargeLocal() (SV_GetServerThreadOwnsGame() ? Sys_IsServerThread() : Sys_IsRenderThread()) + + LargeLocal::LargeLocal(int sizeParam) + { + assert(sizeParam); + assert(Sys_IsMainThread() || CanUseServerLargeLocal()); + + sizeParam = ((sizeParam + (128 - 1)) & ~(128 - 1)); + + if (Sys_IsMainThread()) + { + this->startPos = LargeLocalBegin(sizeParam); + } + else + { + this->startPos = LargeLocalBeginRight(sizeParam); + } + + this->size = sizeParam; + } + + LargeLocal::~LargeLocal() + { + if (this->size) + { + this->PopBuf(); + } + } + + void LargeLocal::PopBuf() + { + assert(this->size); + assert(Sys_IsMainThread() || CanUseServerLargeLocal()); + + if (Sys_IsMainThread()) + { + LargeLocalEnd(this->startPos); + } + else + { + LargeLocalEndRight(this->startPos); + } + + this->size = 0; + } + + void* LargeLocal::GetBuf() const + { + assert(this->size); + assert(Sys_IsMainThread() || CanUseServerLargeLocal()); + + return LargeLocalGetBuf(this->startPos, this->size); + } + + void LargeLocalEnd(int startPos) + { + assert(Sys_IsMainThread()); + assert(g_largeLocalBuf); + + *g_largeLocalPos = startPos; + } + + void LargeLocalEndRight(int startPos) + { + assert(CanUseServerLargeLocal()); + assert(g_largeLocalBuf); + + *g_largeLocalRightPos = startPos; + } + + void* LargeLocalGetBuf(int startPos, int size) + { + assert(Sys_IsMainThread() || CanUseServerLargeLocal()); + assert(g_largeLocalBuf); + assert(!(size & 127)); + + if (Sys_IsMainThread()) + { + return &g_largeLocalBuf[startPos]; + } + + const auto startIndex = startPos - size; + assert(startIndex >= 0); + + return &g_largeLocalBuf[startIndex]; + } +} diff --git a/src/Game/Engine/LargeLocal.hpp b/src/Game/Engine/LargeLocal.hpp new file mode 100644 index 00000000..7dfccab4 --- /dev/null +++ b/src/Game/Engine/LargeLocal.hpp @@ -0,0 +1,29 @@ +#pragma once + +namespace Game::Engine +{ + class LargeLocal + { + public: + explicit LargeLocal(int sizeParam); + ~LargeLocal(); + + LargeLocal(LargeLocal&&) = delete; + LargeLocal(const LargeLocal&) = delete; + LargeLocal& operator=(LargeLocal&&) = delete; + LargeLocal& operator=(const LargeLocal&) = delete; + + void* GetBuf() const; + + private: + void PopBuf(); + + int startPos; + int size; + }; + + extern void LargeLocalEnd(int startPos); + extern void LargeLocalEndRight(int startPos); + + extern void* LargeLocalGetBuf(int startPos, int size); +} diff --git a/src/Game/FileSystem.cpp b/src/Game/FileSystem.cpp new file mode 100644 index 00000000..ce1a5bb7 --- /dev/null +++ b/src/Game/FileSystem.cpp @@ -0,0 +1,62 @@ +#include + +namespace Game +{ + FS_FileExists_t FS_FileExists = FS_FileExists_t(0x4DEFA0); + FS_FreeFile_t FS_FreeFile = FS_FreeFile_t(0x4416B0); + FS_ReadFile_t FS_ReadFile = FS_ReadFile_t(0x4F4B90); + FS_ListFiles_t FS_ListFiles = FS_ListFiles_t(0x441BB0); + FS_FreeFileList_t FS_FreeFileList = FS_FreeFileList_t(0x4A5DE0); + FS_FOpenFileAppend_t FS_FOpenFileAppend = FS_FOpenFileAppend_t(0x410BB0); + FS_FOpenFileWrite_t FS_FOpenFileWrite = FS_FOpenFileWrite_t(0x4BA530); + FS_FOpenTextFileWrite_t FS_FOpenTextFileWrite = FS_FOpenTextFileWrite_t(0x43FD90); + FS_FOpenFileRead_t FS_FOpenFileRead = FS_FOpenFileRead_t(0x46CBF0); + FS_FOpenFileReadDatabase_t FS_FOpenFileReadDatabase = FS_FOpenFileReadDatabase_t(0x42ECA0); + FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread = FS_FOpenFileReadForThread_t(0x643270); + FS_FCloseFile_t FS_FCloseFile = FS_FCloseFile_t(0x462000); + FS_WriteFile_t FS_WriteFile = FS_WriteFile_t(0x426450); + FS_WriteToDemo_t FS_WriteToDemo = FS_WriteToDemo_t(0x4C06E0); + FS_Write_t FS_Write = FS_Write_t(0x4576C0); + FS_Printf_t FS_Printf = FS_Printf_t(0x459320); + FS_Read_t FS_Read = FS_Read_t(0x4A04C0); + FS_Seek_t FS_Seek = FS_Seek_t(0x4A63D0); + FS_FTell_t FS_FTell = FS_FTell_t(0x4E6760); + FS_Remove_t FS_Remove = FS_Remove_t(0x4660F0); + FS_Restart_t FS_Restart = FS_Restart_t(0x461A50); + FS_BuildPathToFile_t FS_BuildPathToFile = FS_BuildPathToFile_t(0x4702C0); + FS_IsShippedIWD_t FS_IsShippedIWD = FS_IsShippedIWD_t(0x642440); + FS_Delete_t FS_Delete = FS_Delete_t(0x48A5B0); + FS_BuildOSPath_t FS_BuildOSPath = FS_BuildOSPath_t(0x4702C0); + + searchpath_t** fs_searchpaths = reinterpret_cast(0x63D96E0); + + int FS_FOpenFileReadCurrentThread(const char* filename, int* file) + { + if (GetCurrentThreadId() == *reinterpret_cast(0x1CDE7FC)) + { + return FS_FOpenFileRead(filename, file); + } + + if (GetCurrentThreadId() == *reinterpret_cast(0x1CDE814)) + { + return FS_FOpenFileReadDatabase(filename, file); + } + + *file = 0; + return -1; + } + + void FS_AddLocalizedGameDirectory(const char* path, const char* dir) + { + static DWORD FS_AddLocalizedGameDirectory_t = 0x642EF0; + + __asm + { + pushad + mov ebx, path + mov eax, dir + call FS_AddLocalizedGameDirectory_t + popad + } + } +} diff --git a/src/Game/FileSystem.hpp b/src/Game/FileSystem.hpp new file mode 100644 index 00000000..e5507fa3 --- /dev/null +++ b/src/Game/FileSystem.hpp @@ -0,0 +1,85 @@ +#pragma once + +namespace Game +{ + typedef void(*FS_FreeFile_t)(void* buffer); + extern FS_FreeFile_t FS_FreeFile; + + typedef int(*FS_ReadFile_t)(const char* path, char** buffer); + extern FS_ReadFile_t FS_ReadFile; + + typedef const char**(*FS_ListFiles_t)(const char* path, const char* extension, FsListBehavior_e behavior, int* numfiles, int allocTrackType); + extern FS_ListFiles_t FS_ListFiles; + + typedef void(*FS_FreeFileList_t)(const char** list, int allocTrackType); + extern FS_FreeFileList_t FS_FreeFileList; + + typedef int(*FS_FOpenFileAppend_t)(const char* filename); + extern FS_FOpenFileAppend_t FS_FOpenFileAppend; + + typedef int(*FS_FOpenFileWrite_t)(const char* filename); + extern FS_FOpenFileWrite_t FS_FOpenFileWrite; + + typedef int(*FS_FOpenTextFileWrite_t)(const char* filename); + extern FS_FOpenTextFileWrite_t FS_FOpenTextFileWrite; + + typedef int(*FS_FOpenFileRead_t)(const char* filename, int* file); + extern FS_FOpenFileRead_t FS_FOpenFileRead; + + typedef int(*FS_FOpenFileReadDatabase_t)(const char* filename, int* file); + extern FS_FOpenFileReadDatabase_t FS_FOpenFileReadDatabase; + + typedef int(*FS_FOpenFileReadForThread_t)(const char* filename, int* file, int thread); + extern FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread; + + typedef int(*FS_FCloseFile_t)(int stream); + extern FS_FCloseFile_t FS_FCloseFile; + + typedef bool(*FS_FileExists_t)(const char* file); + extern FS_FileExists_t FS_FileExists; + + typedef bool(*FS_WriteFile_t)(const char* filename, const char* folder, const void* buffer, int size); + extern FS_WriteFile_t FS_WriteFile; + + typedef int(*FS_WriteToDemo_t)(const void* buffer, int size, int file); + extern FS_WriteToDemo_t FS_WriteToDemo; + + typedef int(*FS_Write_t)(const void* buffer, int len, int h); + extern FS_Write_t FS_Write; + + typedef int(*FS_Printf_t)(int file, const char* fmt, ...); + extern FS_Printf_t FS_Printf; + + typedef int(*FS_Read_t)(void* buffer, size_t size, int file); + extern FS_Read_t FS_Read; + + typedef int(*FS_Seek_t)(int fileHandle, int seekPosition, int seekOrigin); + extern FS_Seek_t FS_Seek; + + typedef int(*FS_FTell_t)(int fileHandle); + extern FS_FTell_t FS_FTell; + + typedef int(*FS_Remove_t)(char*); + extern FS_Remove_t FS_Remove; + + typedef int(*FS_Restart_t)(int localClientNum, int checksumFeed); + extern FS_Restart_t FS_Restart; + + typedef int(*FS_BuildPathToFile_t)(const char*, const char*, const char*, char**); + extern FS_BuildPathToFile_t FS_BuildPathToFile; + + typedef iwd_t* (*FS_IsShippedIWD_t)(const char* fullpath, const char* iwd); + extern FS_IsShippedIWD_t FS_IsShippedIWD; + + typedef int(__cdecl* FS_Delete_t)(const char* fileName); + extern FS_Delete_t FS_Delete; + + typedef void(*FS_BuildOSPath_t)(const char* base, const char* game, const char* qpath, char* ospath); + extern FS_BuildOSPath_t FS_BuildOSPath; + + extern searchpath_t** fs_searchpaths; + + extern int FS_FOpenFileReadCurrentThread(const char* filename, int* file); + + extern void FS_AddLocalizedGameDirectory(const char* path, const char* dir); +} diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index f2e71858..5c6bf69b 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -1,50 +1,18 @@ #include +// Unsorted function definitions namespace Game { - std::vector Sys_ListFilesWrapper(const std::string& directory, const std::string& extension) - { - auto fileCount = 0; - auto** const files = Sys_ListFiles(directory.data(), extension.data(), nullptr, &fileCount, 0); - - std::vector result; - - for (auto i = 0; i < fileCount; i++) - { - if (files[i] != nullptr) - { - result.emplace_back(files[i]); - } - } - - FS_FreeFileList(files); - - return result; - } - - AddRefToObject_t AddRefToObject = AddRefToObject_t(0x61C360); - AllocObject_t AllocObject = AllocObject_t(0x434320); - AddRefToValue_t AddRefToValue = AddRefToValue_t(0x482740); - AllocThread_t AllocThread = AllocThread_t(0x4F78C0); - VM_Execute_0_t VM_Execute_0 = VM_Execute_0_t(0x6222A0); - AngleVectors_t AngleVectors = AngleVectors_t(0x4691A0); - BG_GetNumWeapons_t BG_GetNumWeapons = BG_GetNumWeapons_t(0x4F5CC0); - BG_GetWeaponName_t BG_GetWeaponName = BG_GetWeaponName_t(0x4E6EC0); - BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = BG_LoadWeaponDef_LoadObj_t(0x57B5F0); - BG_LoadWeaponCompleteDefInternal_t BG_LoadWeaponCompleteDefInternal = BG_LoadWeaponCompleteDefInternal_t(0x4B5F10); - BG_GetWeaponDef_t BG_GetWeaponDef = BG_GetWeaponDef_t(0x440EB0); - BG_GetEntityTypeName_t BG_GetEntityTypeName = BG_GetEntityTypeName_t(0x43A0E0); - - Cbuf_AddServerText_t Cbuf_AddServerText = Cbuf_AddServerText_t(0x4BB9B0); + Cbuf_AddServerText_f_t Cbuf_AddServerText_f = Cbuf_AddServerText_f_t(0x4BB9B0); Cbuf_AddText_t Cbuf_AddText = Cbuf_AddText_t(0x404B20); Cbuf_InsertText_t Cbuf_InsertText = Cbuf_InsertText_t(0x4940B0); CG_NextWeapon_f_t CG_NextWeapon_f = CG_NextWeapon_f_t(0x449DE0); CG_GetClientNum_t CG_GetClientNum = CG_GetClientNum_t(0x433700); - CG_PlayBoltedEffect_t CG_PlayBoltedEffect = CG_PlayBoltedEffect_t(0x00430E10); - CG_GetBoneIndex_t CG_GetBoneIndex = CG_GetBoneIndex_t(0x00504F20); + CG_PlayBoltedEffect_t CG_PlayBoltedEffect = CG_PlayBoltedEffect_t(0x430E10); + CG_GetBoneIndex_t CG_GetBoneIndex = CG_GetBoneIndex_t(0x504F20); CG_ScoresDown_f_t CG_ScoresDown_f = CG_ScoresDown_f_t(0x580370); CG_ScoresUp_f_t CG_ScoresUp_f = CG_ScoresUp_f_t(0x5802C0); CG_ScrollScoreboardUp_t CG_ScrollScoreboardUp = CG_ScrollScoreboardUp_t(0x47A5C0); @@ -52,23 +20,6 @@ namespace Game CG_GetTeamName_t CG_GetTeamName = CG_GetTeamName_t(0x4B6210); CG_SetupWeaponDef_t CG_SetupWeaponDef = CG_SetupWeaponDef_t(0x4BD520); - CL_GetClientName_t CL_GetClientName = CL_GetClientName_t(0x4563D0); - CL_IsCgameInitialized_t CL_IsCgameInitialized = CL_IsCgameInitialized_t(0x43EB20); - CL_ConnectFromParty_t CL_ConnectFromParty = CL_ConnectFromParty_t(0x433D30); - CL_DownloadsComplete_t CL_DownloadsComplete = CL_DownloadsComplete_t(0x42CE90); - CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical = CL_DrawStretchPicPhysical_t(0x4FC120); - CL_GetConfigString_t CL_GetConfigString = CL_GetConfigString_t(0x44ADB0); - CL_GetMaxRank_t CL_GetMaxRank = CL_GetMaxRank_t(0x44BA30); - CL_GetRankForXP_t CL_GetRankForXP = CL_GetRankForXP_t(0x4FF8A0); - CL_GetRankIcon_t CL_GetRankIcon = CL_GetRankIcon_t(0x4A7B30); - CL_HandleRelayPacket_t CL_HandleRelayPacket = CL_HandleRelayPacket_t(0x5A8C70); - CL_ResetViewport_t CL_ResetViewport = CL_ResetViewport_t(0x4A8830); - CL_SelectStringTableEntryInDvar_f_t CL_SelectStringTableEntryInDvar_f = CL_SelectStringTableEntryInDvar_f_t(0x4A4560); - CL_DrawStretchPic_t CL_DrawStretchPic = CL_DrawStretchPic_t(0x412490); - CL_ConsoleFixPosition_t CL_ConsoleFixPosition = CL_ConsoleFixPosition_t(0x44A430); - CL_GetLocalClientActiveCount_t CL_GetLocalClientActiveCount = CL_GetLocalClientActiveCount_t(0x5BAD90); - CL_ControllerIndexFromClientNum_t CL_ControllerIndexFromClientNum = CL_ControllerIndexFromClientNum_t(0x449E30); - Cmd_AddCommand_t Cmd_AddCommand = Cmd_AddCommand_t(0x470090); Cmd_AddServerCommand_t Cmd_AddServerCommand = Cmd_AddServerCommand_t(0x4DCE00); Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand = Cmd_ExecuteSingleCommand_t(0x609540); @@ -88,6 +39,7 @@ namespace Game Com_MatchToken_t Com_MatchToken = Com_MatchToken_t(0x447130); Com_SetSlowMotion_t Com_SetSlowMotion = Com_SetSlowMotion_t(0x446E20); Com_Quitf_t Com_Quit_f = Com_Quitf_t(0x4D4000); + Com_OpenLogFile_t Com_OpenLogFile = Com_OpenLogFile_t(0x60A8D0); Con_DrawMiniConsole_t Con_DrawMiniConsole = Con_DrawMiniConsole_t(0x464F30); Con_DrawSolidConsole_t Con_DrawSolidConsole = Con_DrawSolidConsole_t(0x5A5040); @@ -97,47 +49,6 @@ namespace Game DB_PushStreamPos_t DB_PushStreamPos = DB_PushStreamPos_t(0x458A20); DB_PopStreamPos_t DB_PopStreamPos = DB_PopStreamPos_t(0x4D1D60); - DB_BeginRecoverLostDevice_t DB_BeginRecoverLostDevice = DB_BeginRecoverLostDevice_t(0x4BFF90); - DB_EndRecoverLostDevice_t DB_EndRecoverLostDevice = DB_EndRecoverLostDevice_t(0x46B660); - DB_EnumXAssets_t DB_EnumXAssets = DB_EnumXAssets_t(0x4B76D0); - DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal = DB_EnumXAssets_Internal_t(0x5BB0A0); - DB_FindXAssetHeader_t DB_FindXAssetHeader = DB_FindXAssetHeader_t(0x407930); - DB_GetRawBuffer_t DB_GetRawBuffer = DB_GetRawBuffer_t(0x4CDC50); - DB_GetRawFileLen_t DB_GetRawFileLen = DB_GetRawFileLen_t(0x4DAA80); - DB_GetLoadedFraction_t DB_GetLoadedFraction = DB_GetLoadedFraction_t(0x468380); - DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = reinterpret_cast(0x799328); - DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = reinterpret_cast(0x799488); - DB_GetXAssetTypeName_t DB_GetXAssetTypeName = DB_GetXAssetTypeName_t(0x4CFCF0); - DB_IsXAssetDefault_t DB_IsXAssetDefault = DB_IsXAssetDefault_t(0x48E6A0); - DB_LoadXAssets_t DB_LoadXAssets = DB_LoadXAssets_t(0x4E5930); - DB_LoadXFileData_t DB_LoadXFileData = DB_LoadXFileData_t(0x445460); - DB_ReadXFile_t DB_ReadXFile = DB_ReadXFile_t(0x445460); - DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed = DB_ReadXFileUncompressed_t(0x4705E0); - DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers = reinterpret_cast(0x799AB8); - DB_SetXAssetName_t DB_SetXAssetName = DB_SetXAssetName_t(0x453580); - DB_SetXAssetNameHandler_t* DB_SetXAssetNameHandlers = reinterpret_cast(0x7993D8); - DB_XModelSurfsFixup_t DB_XModelSurfsFixup = DB_XModelSurfsFixup_t(0x5BAC50); - - Dvar_RegisterBool_t Dvar_RegisterBool = Dvar_RegisterBool_t(0x4CE1A0); - Dvar_RegisterFloat_t Dvar_RegisterFloat = Dvar_RegisterFloat_t(0x648440); - Dvar_RegisterVec2_t Dvar_RegisterVec2 = Dvar_RegisterVec2_t(0x4F6070); - Dvar_RegisterVec3_t Dvar_RegisterVec3 = Dvar_RegisterVec3_t(0x4EF8E0); - Dvar_RegisterVec4_t Dvar_RegisterVec4 = Dvar_RegisterVec4_t(0x471500); - Dvar_RegisterInt_t Dvar_RegisterInt = Dvar_RegisterInt_t(0x479830); - Dvar_RegisterEnum_t Dvar_RegisterEnum = Dvar_RegisterEnum_t(0x412E40); - Dvar_RegisterString_t Dvar_RegisterString = Dvar_RegisterString_t(0x4FC7E0); - Dvar_RegisterColor_t Dvar_RegisterColor = Dvar_RegisterColor_t(0x4F28E0); - Dvar_RegisterVec3Color_t Dvar_RegisterVec3Color = Dvar_RegisterVec3Color_t(0x4918B0); - - Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName = Dvar_GetUnpackedColorByName_t(0x406530); - Dvar_GetString_t Dvar_GetString = Dvar_GetString_t(0x4EC6B0); - Dvar_GetVariantString_t Dvar_GetVariantString = Dvar_GetVariantString_t(0x4C47E0); - Dvar_FindVar_t Dvar_FindVar = Dvar_FindVar_t(0x4D5390); - Dvar_InfoString_Big_t Dvar_InfoString_Big = Dvar_InfoString_Big_t(0x4D98A0); - Dvar_SetCommand_t Dvar_SetCommand = Dvar_SetCommand_t(0x4EE430); - Dvar_DisplayableValue_t Dvar_DisplayableValue = Dvar_DisplayableValue_t(0x4B5530); - Dvar_Reset_t Dvar_Reset = Dvar_Reset_t(0x4FEFD0); - Encode_Init_t Encode_Init = Encode_Init_t(0x462AB0); Field_Clear_t Field_Clear = Field_Clear_t(0x437EB0); @@ -145,40 +56,6 @@ namespace Game FreeMemory_t FreeMemory = FreeMemory_t(0x4D6640); Free_String_t Free_String = Free_String_t(0x470E80); - FS_FileExists_t FS_FileExists = FS_FileExists_t(0x4DEFA0); - FS_FreeFile_t FS_FreeFile = FS_FreeFile_t(0x4416B0); - FS_ReadFile_t FS_ReadFile = FS_ReadFile_t(0x4F4B90); - FS_GetFileList_t FS_GetFileList = FS_GetFileList_t(0x441BB0); - FS_FreeFileList_t FS_FreeFileList = FS_FreeFileList_t(0x4A5DE0); - FS_FOpenFileAppend_t FS_FOpenFileAppend = FS_FOpenFileAppend_t(0x410BB0); - FS_FOpenFileAppend_t FS_FOpenFileWrite = FS_FOpenFileAppend_t(0x4BA530); - FS_FOpenFileRead_t FS_FOpenFileRead = FS_FOpenFileRead_t(0x46CBF0); - FS_FOpenFileRead_t FS_FOpenFileReadDatabase = FS_FOpenFileRead_t(0x42ECA0); - FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread = FS_FOpenFileReadForThread_t(0x643270); - FS_FCloseFile_t FS_FCloseFile = FS_FCloseFile_t(0x462000); - FS_WriteFile_t FS_WriteFile = FS_WriteFile_t(0x426450); - FS_WriteToDemo_t FS_WriteToDemo = FS_WriteToDemo_t(0x4C06E0); - FS_Write_t FS_Write = FS_Write_t(0x4576C0); - FS_Printf_t FS_Printf = FS_Printf_t(0x459320); - FS_Read_t FS_Read = FS_Read_t(0x4A04C0); - FS_Seek_t FS_Seek = FS_Seek_t(0x4A63D0); - FS_FTell_t FS_FTell = FS_FTell_t(0x4E6760); - FS_Remove_t FS_Remove = FS_Remove_t(0x4660F0); - FS_Restart_t FS_Restart = FS_Restart_t(0x461A50); - FS_BuildPathToFile_t FS_BuildPathToFile = FS_BuildPathToFile_t(0x4702C0); - FS_IsShippedIWD_t FS_IsShippedIWD = FS_IsShippedIWD_t(0x642440); - FS_Delete_t FS_Delete = FS_Delete_t(0x48A5B0); - - G_LogPrintf_t G_LogPrintf = G_LogPrintf_t(0x4B0150); - G_GetWeaponIndexForName_t G_GetWeaponIndexForName = G_GetWeaponIndexForName_t(0x49E540); - G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = G_SpawnEntitiesFromString_t(0x4D8840); - G_Spawn_t G_Spawn = G_Spawn_t(0x4226F0); - G_FreeEntity_t G_FreeEntity = G_FreeEntity_t(0x44C9D0); - G_SpawnItem_t G_SpawnItem = G_SpawnItem_t(0x403770); - G_GetItemClassname_t G_GetItemClassname = G_GetItemClassname_t(0x492630); - G_PrintEntities_t G_PrintEntities = G_PrintEntities_t(0x4E6A50); - G_GetEntityTypeName_t G_GetEntityTypeName = G_GetEntityTypeName_t(0x4EB810); - Svcmd_EntityList_f_t Svcmd_EntityList_f = Svcmd_EntityList_f_t(0x4B6A70); GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript = GScr_LoadGameTypeScript_t(0x4ED9A0); @@ -236,6 +113,7 @@ namespace Game MSG_WriteLong_t MSG_WriteLong = MSG_WriteLong_t(0x41CA20); MSG_WriteShort_t MSG_WriteShort = MSG_WriteShort_t(0x503B90); MSG_WriteString_t MSG_WriteString = MSG_WriteString_t(0x463820); + MSG_ReadDeltaUsercmdKey_t MSG_ReadDeltaUsercmdKey = MSG_ReadDeltaUsercmdKey_t(0x491F00); MSG_WriteBitsCompress_t MSG_WriteBitsCompress = MSG_WriteBitsCompress_t(0x4319D0); MSG_ReadByte_t MSG_ReadByte = MSG_ReadByte_t(0x4C1C20); MSG_ReadBitsCompress_t MSG_ReadBitsCompress = MSG_ReadBitsCompress_t(0x4DCC30); @@ -251,11 +129,13 @@ namespace Game NET_StringToAdr_t NET_StringToAdr = NET_StringToAdr_t(0x409010); NET_OutOfBandPrint_t NET_OutOfBandPrint = NET_OutOfBandPrint_t(0x4AEF00); NET_OutOfBandData_t NET_OutOfBandData = NET_OutOfBandData_t(0x49C7E0); + NET_OutOfBandVoiceData_t NET_OutOfBandVoiceData = NET_OutOfBandVoiceData_t(0x4FCC90); Live_MPAcceptInvite_t Live_MPAcceptInvite = Live_MPAcceptInvite_t(0x420A6D); Live_GetMapIndex_t Live_GetMapIndex = Live_GetMapIndex_t(0x4F6440); Live_GetPrestige_t Live_GetPrestige = Live_GetPrestige_t(0x430F90); Live_GetXp_t Live_GetXp = Live_GetXp_t(0x404C60); + Live_GetLocalClientName_t Live_GetLocalClientName = Live_GetLocalClientName_t(0x441FC0); LiveStorage_GetStat_t LiveStorage_GetStat = LiveStorage_GetStat_t(0x471F60); @@ -269,6 +149,7 @@ namespace Game PartyHost_CountMembers_t PartyHost_CountMembers = PartyHost_CountMembers_t(0x497330); PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot = PartyHost_GetMemberAddressBySlot_t(0x44E100); PartyHost_GetMemberName_t PartyHost_GetMemberName = PartyHost_GetMemberName_t(0x44BE90); + Party_InParty_t Party_InParty = Party_InParty_t(0x4F10C0); Playlist_ParsePlaylists_t Playlist_ParsePlaylists = Playlist_ParsePlaylists_t(0x4295A0); @@ -283,58 +164,6 @@ namespace Game R_FlushSun_t R_FlushSun = R_FlushSun_t(0x53FB50); R_SortWorldSurfaces_t R_SortWorldSurfaces = R_SortWorldSurfaces_t(0x53DC10); - RemoveRefToObject_t RemoveRefToObject = RemoveRefToObject_t(0x437190); - - Scr_LoadGameType_t Scr_LoadGameType = Scr_LoadGameType_t(0x4D9520); - Scr_StartupGameType_t Scr_StartupGameType = Scr_StartupGameType_t(0x438720); - - Scr_LoadScript_t Scr_LoadScript = Scr_LoadScript_t(0x45D940); - Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0); - - Scr_GetString_t Scr_GetString = Scr_GetString_t(0x425900); - Scr_GetConstString_t Scr_GetConstString = Scr_GetConstString_t(0x494830); - Scr_GetDebugString_t Scr_GetDebugString = Scr_GetDebugString_t(0x4EBF50); - Scr_GetFloat_t Scr_GetFloat = Scr_GetFloat_t(0x443140); - Scr_GetInt_t Scr_GetInt = Scr_GetInt_t(0x4F31D0); - Scr_GetObject_t Scr_GetObject = Scr_GetObject_t(0x462100); - Scr_GetNumParam_t Scr_GetNumParam = Scr_GetNumParam_t(0x4B0E90); - Scr_GetEntityId_t Scr_GetEntityId = Scr_GetEntityId_t(0x4165E0); - - Scr_ExecThread_t Scr_ExecThread = Scr_ExecThread_t(0x4AD0B0); - Scr_FreeThread_t Scr_FreeThread = Scr_FreeThread_t(0x4BD320); - - Scr_AddEntity_t Scr_AddEntity = Scr_AddEntity_t(0x4BFB40); - Scr_AddString_t Scr_AddString = Scr_AddString_t(0x412310); - Scr_AddConstString_t Scr_AddConstString = Scr_AddConstString_t(0x488860); - Scr_AddIString_t Scr_AddIString = Scr_AddIString_t(0x455F20); - Scr_AddInt_t Scr_AddInt = Scr_AddInt_t(0x41D7D0); - Scr_AddFloat_t Scr_AddFloat = Scr_AddFloat_t(0x61E860); - Scr_AddObject_t Scr_AddObject = Scr_AddObject_t(0x430F40); - Scr_Notify_t Scr_Notify = Scr_Notify_t(0x4A4750); - Scr_NotifyLevel_t Scr_NotifyLevel = Scr_NotifyLevel_t(0x4D9C30); - - Scr_Error_t Scr_Error = Scr_Error_t(0x61E8B0); - Scr_ObjectError_t Scr_ObjectError = Scr_ObjectError_t(0x42EF40); - Scr_ParamError_t Scr_ParamError = Scr_ParamError_t(0x4FBC70); - - Scr_GetType_t Scr_GetType = Scr_GetType_t(0x422900); - Scr_GetPointerType_t Scr_GetPointerType = Scr_GetPointerType_t(0x4828E0); - - Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0); - - Scr_GetObjectField_t Scr_GetObjectField = Scr_GetObjectField_t(0x4FF3D0); - Scr_SetObjectField_t Scr_SetObjectField = Scr_SetObjectField_t(0x4F20F0); - Scr_GetEntityField_t Scr_GetEntityField = Scr_GetEntityField_t(0x4E8390); - Scr_SetClientField_t Scr_SetClientField = Scr_SetClientField_t(0x4A6DF0); - Scr_AddClassField_t Scr_AddClassField = Scr_AddClassField_t(0x4C0E70); - - GetEntity_t GetEntity = GetEntity_t(0x4BC270); - GetPlayerEntity_t GetPlayerEntity = GetPlayerEntity_t(0x49C4A0); - - Scr_RegisterFunction_t Scr_RegisterFunction = Scr_RegisterFunction_t(0x492D50); - Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode = Scr_ShutdownAllocNode_t(0x441650); - Scr_IsSystemActive_t Scr_IsSystemActive = Scr_IsSystemActive_t(0x4B24E0); - Script_Alloc_t Script_Alloc = Script_Alloc_t(0x422E70); Script_SetupTokens_t Script_SetupTokens = Script_SetupTokens_t(0x4E6950); Script_CleanString_t Script_CleanString = Script_CleanString_t(0x498220); @@ -369,38 +198,6 @@ namespace Game StringTable_GetColumnValueForRow_t StringTable_GetColumnValueForRow = StringTable_GetColumnValueForRow_t(0x4F2C80); StringTable_HashString_t StringTable_HashString = StringTable_HashString_t(0x475EB0); - SV_AddTestClient_t SV_AddTestClient = SV_AddTestClient_t(0x48AD30); - SV_IsTestClient_t SV_IsTestClient = SV_IsTestClient_t(0x4D6E40); - SV_GameClientNum_Score_t SV_GameClientNum_Score = SV_GameClientNum_Score_t(0x469AC0); - SV_GameSendServerCommand_t SV_GameSendServerCommand = SV_GameSendServerCommand_t(0x4BC3A0); - SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString = SV_Cmd_TokenizeString_t(0x4B5780); - SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString = SV_Cmd_EndTokenizedString_t(0x464750); - SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer = SV_Cmd_ArgvBuffer_t(0x40BB60); - SV_DirectConnect_t SV_DirectConnect = SV_DirectConnect_t(0x460480); - SV_SetConfigstring_t SV_SetConfigstring = SV_SetConfigstring_t(0x4982E0); - SV_Loaded_t SV_Loaded = SV_Loaded_t(0x4EE3E0); - SV_ClientThink_t SV_ClientThink = SV_ClientThink_t(0x44ADD0); - SV_DropClient_t SV_DropClient = SV_DropClient_t(0x4D1600); - SV_GetPlayerByName_t SV_GetPlayerByName = SV_GetPlayerByName_t(0x6242B0); - SV_GetPlayerByNum_t SV_GetPlayerByNum = SV_GetPlayerByNum_t(0x624390); - - Sys_FreeFileList_t Sys_FreeFileList = Sys_FreeFileList_t(0x4D8580); - Sys_IsDatabaseReady_t Sys_IsDatabaseReady = Sys_IsDatabaseReady_t(0x4CA4A0); - Sys_IsDatabaseReady2_t Sys_IsDatabaseReady2 = Sys_IsDatabaseReady2_t(0x441280); - Sys_IsMainThread_t Sys_IsMainThread = Sys_IsMainThread_t(0x4C37D0); - Sys_IsRenderThread_t Sys_IsRenderThread = Sys_IsRenderThread_t(0x4B20E0); - Sys_IsServerThread_t Sys_IsServerThread = Sys_IsServerThread_t(0x4B0270); - Sys_IsDatabaseThread_t Sys_IsDatabaseThread = Sys_IsDatabaseThread_t(0x4C6020); - Sys_SendPacket_t Sys_SendPacket = Sys_SendPacket_t(0x60FDC0); - Sys_ShowConsole_t Sys_ShowConsole = Sys_ShowConsole_t(0x4305E0); - Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads = Sys_SuspendOtherThreads_t(0x45A190); - Sys_ListFiles_t Sys_ListFiles = Sys_ListFiles_t(0x45A660); - Sys_Milliseconds_t Sys_Milliseconds = Sys_Milliseconds_t(0x42A660); - Sys_Error_t Sys_Error = Sys_Error_t(0x43D570); - Sys_LockWrite_t Sys_LockWrite = Sys_LockWrite_t(0x435880); - Sys_TempPriorityAtLeastNormalBegin_t Sys_TempPriorityAtLeastNormalBegin = Sys_TempPriorityAtLeastNormalBegin_t(0x478680); - Sys_TempPriorityEnd_t Sys_TempPriorityEnd = Sys_TempPriorityEnd_t(0x4DCF00); - TeleportPlayer_t TeleportPlayer = TeleportPlayer_t(0x496850); UI_AddMenuList_t UI_AddMenuList = UI_AddMenuList_t(0x4533C0); @@ -419,6 +216,7 @@ namespace Game UI_KeyEvent_t UI_KeyEvent = UI_KeyEvent_t(0x4970F0); UI_SafeTranslateString_t UI_SafeTranslateString = UI_SafeTranslateString_t(0x4F1700); UI_ReplaceConversions_t UI_ReplaceConversions = UI_ReplaceConversions_t(0x4E9740); + UI_ParseInfos_t UI_ParseInfos = UI_ParseInfos_t(0x4027A0); Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0); @@ -448,8 +246,8 @@ namespace Game PM_playerTrace_t PM_playerTrace = PM_playerTrace_t(0x458980); PM_Trace_t PM_Trace = PM_Trace_t(0x441F60); PM_GetEffectiveStance_t PM_GetEffectiveStance = PM_GetEffectiveStance_t(0x412540); + PM_UpdateLean_t PM_UpdateLean = PM_UpdateLean_t(0x43DED0); - CL_MouseEvent_t CL_MouseEvent = CL_MouseEvent_t(0x4D7C50); IN_RecenterMouse_t IN_RecenterMouse = IN_RecenterMouse_t(0x463D80); IN_MouseMove_t IN_MouseMove = IN_MouseMove_t(0x64C490); @@ -472,9 +270,15 @@ namespace Game Z_VirtualAlloc_t Z_VirtualAlloc = Z_VirtualAlloc_t(0x4CFBA0); I_strncpyz_t I_strncpyz = I_strncpyz_t(0x4D6F80); + I_CleanStr_t I_CleanStr = I_CleanStr_t(0x4AD470); - XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); - unsigned int* g_poolSize = reinterpret_cast(0x7995E8); + XNAddrToString_t XNAddrToString = XNAddrToString_t(0x452690); + + Voice_IncomingVoiceData_t Voice_IncomingVoiceData = Voice_IncomingVoiceData_t(0x5001A0); + Voice_IsClientTalking_t Voice_IsClientTalking = Voice_IsClientTalking_t(0x4D9D20); + + LargeLocalBegin_t LargeLocalBegin = LargeLocalBegin_t(0x4127A0); + LargeLocalBeginRight_t LargeLocalBeginRight = LargeLocalBeginRight_t(0x644140); CmdArgs* cmd_args = reinterpret_cast(0x1AAC5D0); CmdArgs* sv_cmd_args = reinterpret_cast(0x1ACF8A0); @@ -484,13 +288,8 @@ namespace Game source_t **sourceFiles = reinterpret_cast(0x7C4A98); keywordHash_t **menuParseKeywordHash = reinterpret_cast(0x63AE928); - float* cl_angles = reinterpret_cast(0xB2F8D0); float* cgameFOVSensitivityScale = reinterpret_cast(0xB2F884); - int* svs_time = reinterpret_cast(0x31D9384); - int* svs_clientCount = reinterpret_cast(0x31D938C); - client_t* svs_clients = reinterpret_cast(0x31D9390); - UiContext* uiContext = reinterpret_cast(0x62E2858); int* arenaCount = reinterpret_cast(0x62E6930); @@ -499,16 +298,12 @@ namespace Game int* gameTypeCount = reinterpret_cast(0x62E50A0); gameTypeName_t* gameTypes = reinterpret_cast(0x62E50A4); - searchpath_t** fs_searchpaths = reinterpret_cast(0x63D96E0); - - XBlock** g_streamBlocks = reinterpret_cast(0x16E554C); - int* g_streamPos = reinterpret_cast(0x16E5554); - int* g_streamPosIndex = reinterpret_cast(0x16E5578); - bool* g_lobbyCreateInProgress = reinterpret_cast(0x66C9BC2); PartyData* g_lobbyData = reinterpret_cast(0x1081C00); PartyData* g_partyData = reinterpret_cast(0x107E500); + SessionData* g_serverSession = reinterpret_cast(0x66B7008); + int* numIP = reinterpret_cast(0x64A1E68); netIP_t* localIP = reinterpret_cast(0x64A1E28); @@ -517,8 +312,6 @@ namespace Game int* demoRecording = reinterpret_cast(0xA5EA08); int* serverMessageSequence = reinterpret_cast(0xA3E9B4); - gentity_t* g_entities = reinterpret_cast(0x18835D8); - netadr_t* connectedHost = reinterpret_cast(0xA1E888); SOCKET* ip_socket = reinterpret_cast(0x64A3008); @@ -554,12 +347,6 @@ namespace Game infoParm_t* infoParams = reinterpret_cast(0x79D260); // Count 0x1E - XZone* g_zones = reinterpret_cast(0x14C0F80); - unsigned short* db_hashTable = reinterpret_cast(0x12412B0); - - scrVmPub_t* scrVmPub = reinterpret_cast(0x2040CF0); - scrVarPub_t* scrVarPub = reinterpret_cast(0x201A408); - clientState_t* clcState = reinterpret_cast(0xB2C540); GfxScene* scene = reinterpret_cast(0x6944914); @@ -571,9 +358,6 @@ namespace Game float* g_console_char_height = reinterpret_cast(0x798550); field_t* g_consoleField = reinterpret_cast(0xA1B6B0); - clientStatic_t* cls = reinterpret_cast(0xA7FE90); - clientUIActive_t* clientUIActives = reinterpret_cast(0xB2BB8A); - sharedUiInfo_t* sharedUiInfo = reinterpret_cast(0x62E4B78); ScreenPlacement* scrPlaceFull = reinterpret_cast(0x10843F0); ScreenPlacement* scrPlaceFullUnsafe = reinterpret_cast(0x1084460); @@ -597,8 +381,6 @@ namespace Game XModel** cached_models = reinterpret_cast(0x1AA20C8); - FastCriticalSection* db_hashCritSect = reinterpret_cast(0x16B8A54); - float (*CorrectSolidDeltas)[26][3] = reinterpret_cast(0x739BB8); // Count 26 level_locals_t* level = reinterpret_cast(0x1A831A8); @@ -624,42 +406,22 @@ namespace Game int* com_errorPrintsCount = reinterpret_cast(0x1AD7910); - scr_const_t* scr_const = reinterpret_cast(0x1AA2E00); - - clientConnection_t* clientConnections = reinterpret_cast(0xA1E878); - unsigned int* playerCardUIStringIndex = reinterpret_cast(0x62CD7A8); char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38] = reinterpret_cast(0x62CB4F8); + uiInfo_s* uiInfoArray = reinterpret_cast(0x62E2858); + + int* logfile = reinterpret_cast(0x1AD8F28); + GamerSettingState* gamerSettings = reinterpret_cast(0x107D3E8); - void Sys_LockRead(FastCriticalSection* critSect) - { - InterlockedIncrement(&critSect->readCount); - while (critSect->writeCount) std::this_thread::sleep_for(1ms); - } + unsigned char* g_largeLocalBuf = reinterpret_cast(0x63D9790); + int* g_largeLocalPos = reinterpret_cast(0x63D97B4); + int* g_largeLocalRightPos = reinterpret_cast(0x63D9780); - void Sys_UnlockRead(FastCriticalSection* critSect) - { - assert(critSect->readCount > 0); - InterlockedDecrement(&critSect->readCount); - } - - XModel* G_GetModel(const int index) - { - assert(index > 0); - assert(index < MAX_MODELS); - return cached_models[index]; - } - - XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize) - { - int elSize = DB_GetXAssetSizeHandlers[type](); - XAssetHeader poolEntry = { Utils::Memory::GetAllocator()->allocate(newSize * elSize) }; - DB_XAssetPool[type] = poolEntry; - g_poolSize[type] = newSize; - return poolEntry; - } + char** ui_arenaInfos = reinterpret_cast(0x62D2688); + int* ui_numArenas = reinterpret_cast(0x62D2788); + int* ui_arenaBufPos = reinterpret_cast(0x62D278C); const char* TableLookup(StringTable* stringtable, int row, int column) { @@ -708,102 +470,10 @@ namespace Game return gameType; } - const char *DB_GetXAssetName(XAsset *asset) - { - if (!asset) return ""; - return DB_GetXAssetNameHandlers[asset->type](&asset->header); - } - - XAssetType DB_GetXAssetNameType(const char* name) - { - for (int i = 0; i < ASSET_TYPE_COUNT; ++i) - { - XAssetType type = static_cast(i); - if (!_stricmp(DB_GetXAssetTypeName(type), name)) - { - // Col map workaround! - if (type == Game::XAssetType::ASSET_TYPE_CLIPMAP_SP) - { - return Game::XAssetType::ASSET_TYPE_CLIPMAP_MP; - } - - return type; - } - } - - return ASSET_TYPE_INVALID; - } - - int DB_GetZoneIndex(const std::string& name) - { - for (int i = 0; i < 32; ++i) - { - if (Game::g_zones[i].name == name) - { - return i; - } - } - - return -1; - } - - bool DB_IsZoneLoaded(const char* zone) - { - int zoneCount = Utils::Hook::Get(0x1261BCC); - char* zoneIndices = reinterpret_cast(0x16B8A34); - char* zoneData = reinterpret_cast(0x14C0F80); - - for (int i = 0; i < zoneCount; ++i) - { - std::string name = zoneData + 4 + 0xA4 * (zoneIndices[i] & 0xFF); - - if (name == zone) - { - return true; - } - } - - return false; - } - - void DB_EnumXAssetEntries(XAssetType type, std::function callback, bool overrides) - { - Sys_LockRead(db_hashCritSect); - - const auto pool = Components::Maps::GetAssetEntryPool(); - for(auto hash = 0; hash < 37000; hash++) - { - auto hashIndex = db_hashTable[hash]; - while(hashIndex) - { - auto* assetEntry = &pool[hashIndex]; - - if(assetEntry->asset.type == type) - { - callback(assetEntry); - if (overrides) - { - auto overrideIndex = assetEntry->nextOverride; - while (overrideIndex) - { - auto* overrideEntry = &pool[overrideIndex]; - callback(overrideEntry); - overrideIndex = overrideEntry->nextOverride; - } - } - } - - hashIndex = assetEntry->nextHash; - } - } - - Sys_UnlockRead(db_hashCritSect); - } - // this cant be MessageBox because windows.h has a define that converts it to MessageBoxW. which is just stupid void ShowMessageBox(const std::string& message, const std::string& title) { - if (!Game::CL_IsCgameInitialized()) + if (!CL_IsCgameInitialized()) { Dvar_SetStringByName("com_errorMessage", message.data()); Dvar_SetStringByName("com_errorTitle", title.data()); @@ -838,68 +508,6 @@ namespace Game return hash; } - void SV_GameDropClient(int clientNum, const char* reason) - { - const auto maxClients = Dvar_FindVar("sv_maxclients")->current.integer; - assert(maxClients >= 1 && maxClients <= 18); - - if (clientNum >= 0 && clientNum < maxClients) - { - SV_DropClient(&svs_clients[clientNum], reason, true); - } - } - - void SV_DropAllBots() - { - for (auto i = 0; i < *svs_clientCount; ++i) - { - if (svs_clients[i].state != CS_FREE - && svs_clients[i].netchan.remoteAddress.type == NA_BOT) - { - SV_GameDropClient(i, "GAME_GET_TO_COVER"); - } - } - } - - void IncInParam() - { - Scr_ClearOutParams(); - - if (scrVmPub->top == scrVmPub->maxStack) - { - Sys_Error("Internal script stack overflow"); - } - - scrVmPub->top++; - scrVmPub->inparamcount++; - } - - void Scr_AddBool(int value) - { - assert(value == 0 || value == 1); - - IncInParam(); - scrVmPub->top->type = VAR_INTEGER; - scrVmPub->top->u.intValue = value; - } - - int FS_FOpenFileReadCurrentThread(const char* file, int* fh) - { - if (GetCurrentThreadId() == *reinterpret_cast(0x1CDE7FC)) - { - return FS_FOpenFileRead(file, fh); - } - else if (GetCurrentThreadId() == *reinterpret_cast(0x1CDE814)) - { - return FS_FOpenFileReadDatabase(file, fh); - } - else - { - *fh = NULL; - return -1; - } - } - void Load_IndexBuffer(void* data, IDirect3DIndexBuffer9** storeHere, int count) { if (Components::Dvar::Var("r_loadForRenderer").get()) @@ -916,19 +524,19 @@ namespace Game char* Com_GetParseThreadInfo() { - if (Game::Sys_IsMainThread()) + if (Sys_IsMainThread()) { return reinterpret_cast(0x6466628); } - if (Game::Sys_IsRenderThread()) + if (Sys_IsRenderThread()) { return reinterpret_cast(0x646AC34); } - if (Game::Sys_IsServerThread()) + if (Sys_IsServerThread()) { return reinterpret_cast(0x646F240); } - if (Game::Sys_IsDatabaseThread()) + if (Sys_IsDatabaseThread()) { return reinterpret_cast(0x647384C); } @@ -946,13 +554,6 @@ namespace Game } } - int CL_GetMaxXP() - { - StringTable* rankTable = DB_FindXAssetHeader(ASSET_TYPE_STRINGTABLE, "mp/rankTable.csv").stringTable; - const char* maxrank = StringTable_Lookup(rankTable, 0, "maxrank", 1); - return atoi(StringTable_Lookup(rankTable, 0, maxrank, 7)); - } - void Vec2UnpackTexCoords(const PackedTexCoords in, vec2_t* out) { unsigned int v3; // xmm1_4 @@ -1028,7 +629,7 @@ namespace Game void R_AddDebugBounds(float* color, Bounds* b) { - Game::vec3_t v1, v2, v3, v4, v5, v6, v7, v8; + vec3_t v1, v2, v3, v4, v5, v6, v7, v8; float* center = b->midPoint; float* halfSize = b->halfSize; @@ -1065,22 +666,22 @@ namespace Game v8[2] = center[2] + halfSize[2]; // bottom - Game::R_AddDebugLine(color, v1, v2); - Game::R_AddDebugLine(color, v2, v4); - Game::R_AddDebugLine(color, v4, v3); - Game::R_AddDebugLine(color, v3, v1); + R_AddDebugLine(color, v1, v2); + R_AddDebugLine(color, v2, v4); + R_AddDebugLine(color, v4, v3); + R_AddDebugLine(color, v3, v1); // top - Game::R_AddDebugLine(color, v5, v6); - Game::R_AddDebugLine(color, v6, v8); - Game::R_AddDebugLine(color, v8, v7); - Game::R_AddDebugLine(color, v7, v5); + R_AddDebugLine(color, v5, v6); + R_AddDebugLine(color, v6, v8); + R_AddDebugLine(color, v8, v7); + R_AddDebugLine(color, v7, v5); // verticals - Game::R_AddDebugLine(color, v1, v5); - Game::R_AddDebugLine(color, v2, v6); - Game::R_AddDebugLine(color, v3, v7); - Game::R_AddDebugLine(color, v4, v8); + R_AddDebugLine(color, v1, v5); + R_AddDebugLine(color, v2, v6); + R_AddDebugLine(color, v3, v7); + R_AddDebugLine(color, v4, v8); } void R_AddDebugBounds(float* color, Bounds* b, const float(*quat)[4]) @@ -1130,22 +731,22 @@ namespace Game } // bottom - Game::R_AddDebugLine(color, v[0], v[1]); - Game::R_AddDebugLine(color, v[1], v[3]); - Game::R_AddDebugLine(color, v[3], v[2]); - Game::R_AddDebugLine(color, v[2], v[0]); + R_AddDebugLine(color, v[0], v[1]); + R_AddDebugLine(color, v[1], v[3]); + R_AddDebugLine(color, v[3], v[2]); + R_AddDebugLine(color, v[2], v[0]); // top - Game::R_AddDebugLine(color, v[4], v[5]); - Game::R_AddDebugLine(color, v[5], v[7]); - Game::R_AddDebugLine(color, v[7], v[6]); - Game::R_AddDebugLine(color, v[6], v[4]); + R_AddDebugLine(color, v[4], v[5]); + R_AddDebugLine(color, v[5], v[7]); + R_AddDebugLine(color, v[7], v[6]); + R_AddDebugLine(color, v[6], v[4]); // verticals - Game::R_AddDebugLine(color, v[0], v[4]); - Game::R_AddDebugLine(color, v[1], v[5]); - Game::R_AddDebugLine(color, v[2], v[6]); - Game::R_AddDebugLine(color, v[3], v[7]); + R_AddDebugLine(color, v[0], v[4]); + R_AddDebugLine(color, v[1], v[5]); + R_AddDebugLine(color, v[2], v[6]); + R_AddDebugLine(color, v[3], v[7]); } float GraphGetValueFromFraction(const int knotCount, const float(*knots)[2], const float fraction) @@ -1180,29 +781,66 @@ namespace Game void UI_FilterStringForButtonAnimation(char* str, unsigned int strMaxSize) { - if (SEH_GetCurrentLanguage() == 8 || Sys_Milliseconds() % 1000 <= 800) + if (SEH_GetCurrentLanguage() == 8) { return; } - size_t i = 0; - while (str[i] != '\0') + const auto remainder = Sys_Milliseconds() % 1000; + if (remainder <= 800) { - if (i >= strMaxSize) - break; - - const auto value = str[i]; - if (value == 16) - { - str[i] = -68; - } - else if (value == 17) - { - str[i] = -67; - } - - ++i; + return; } + + for (std::size_t idx = 0; str[idx] && idx < strMaxSize; ++idx) + { + if (str[idx] == 16) + { + str[idx] = -68; + } + else if (str[idx] == 17) + { + str[idx] = -67; + } + } + } + + void I_strncpyz_s(char* dest, std::size_t destsize, const char* src, std::size_t count) + { + if (!destsize && !dest) + { + return; + } + if (!src || !count) + { + *dest = '\0'; + } + else + { + const auto* p = reinterpret_cast(src - 1); + auto* q = reinterpret_cast(dest - 1); + auto n = count + 1; + auto s = count; + if (destsize <= count) + { + n = destsize + 1; + s = destsize - 1; + } + do + { + if (!--n) + { + dest[s] = '\0'; + return; + } + *++q = *++p; + } while (*q); + } + } + + void I_strcpy(char* dest, std::size_t destsize, const char* src) + { + I_strncpyz_s(dest, destsize, src, destsize); } #pragma optimize("", off) @@ -1224,50 +862,6 @@ namespace Game } } - __declspec(naked) XAssetHeader DB_FindXAssetDefaultHeaderInternal(XAssetType /*type*/) - { - __asm - { - push eax - pushad - - mov eax, 5BB210h - mov edi, [esp + 28h] - call eax - - mov [esp + 20h], eax - popad - pop eax - - retn - } - } - - __declspec(naked) XAssetEntry* DB_FindXAssetEntry(XAssetType /*type*/, const char* /*name*/) - { - __asm - { - push eax - pushad - - mov edi, [esp + 2Ch] // name - push edi - - mov edi, [esp + 2Ch] // type - - mov eax, 5BB1B0h - call eax - - add esp, 4h - - mov [esp + 20h], eax - popad - pop eax - - retn - } - } - __declspec(naked) bool PM_IsAdsAllowed(playerState_s* /*ps*/) { __asm @@ -1287,23 +881,6 @@ namespace Game } } - __declspec(naked) void FS_AddLocalizedGameDirectory(const char* /*path*/, const char* /*dir*/) - { - __asm - { - pushad - - mov ebx, [esp + 24h] - mov eax, [esp + 28h] - mov ecx, 642EF0h - call ecx - - popad - - retn - } - } - __declspec(naked) void R_LoadSunThroughDvars(const char* /*mapname*/, sunflare_t* /*sun*/) { __asm @@ -1336,48 +913,6 @@ namespace Game } } - __declspec(naked) void Scr_NotifyId(unsigned int /*id*/, unsigned __int16 /*stringValue*/, unsigned int /*paramcount*/) - { - __asm - { - pushad - - mov eax, [esp + 2Ch] // paramcount - - push [esp + 28h] // stringValue - push [esp + 28h] // id - - mov edx, 61E670h // Scr_NotifyId - call edx - - add esp, 8h - - popad - retn - } - } - - __declspec(naked) void RuntimeErrorInternal(int /*channel*/, const char* /*codePos*/, unsigned int /*index*/, const char* /*msg*/) - { - __asm - { - pushad - - mov eax, [esp + 0x10 + 0x20] // msg - mov edi, [esp + 0x4 + 0x20] // channel - - push [esp + 0xC + 0x20] // index - push [esp + 0xC + 0x20] // codePos - - mov edx, 0x61ABE0 - call edx - add esp, 0x8 - - popad - ret - } - } - __declspec(naked) void IN_KeyUp(kbutton_t* /*button*/) { __asm @@ -1460,7 +995,7 @@ namespace Game } } - void Menu_SetNextCursorItem(Game::UiContext* a1, Game::menuDef_t* a2, int unk) + void Menu_SetNextCursorItem(UiContext* a1, menuDef_t* a2, int unk) { __asm { @@ -1473,7 +1008,7 @@ namespace Game } } - void Menu_SetPrevCursorItem(Game::UiContext* a1, Game::menuDef_t* a2, int unk) + void Menu_SetPrevCursorItem(UiContext* a1, menuDef_t* a2, int unk) { __asm { @@ -1548,8 +1083,8 @@ namespace Game Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter) { - static auto R_GetCharacterGlyph_Func = 0x5055C0; - Glyph* returnValue; + static auto R_GetCharacterGlyph_t = 0x5055C0; + Glyph* result; __asm { @@ -1557,14 +1092,14 @@ namespace Game mov edi, letter push font - call R_GetCharacterGlyph_Func + call R_GetCharacterGlyph_t add esp, 4 - mov returnValue, eax + mov result, eax popad } - return returnValue; + return result; } __declspec(naked) bool SetupPulseFXVars(const char* /*text*/, int /*maxLength*/, int /*fxBirthTime*/, int /*fxLetterTime*/, int /*fxDecayStartTime*/, int /*fxDecayDuration*/, bool* /*resultDrawRandChar*/, int* /*resultRandSeed*/, int* /*resultMaxLength*/, bool* /*resultDecaying*/, int* /*resultDecayTimeElapsed*/) @@ -1689,48 +1224,6 @@ namespace Game } } - __declspec(naked) void Dvar_SetVariant(dvar_t*, DvarValue, DvarSetSource) - { - __asm - { - pushad - - mov eax, [esp + 0x4 + 0x20] // dvar - push [esp + 0x18 + 0x20] // source - push [esp + 0x18 + 0x20] // value - push [esp + 0x18 + 0x20] // value - push [esp + 0x18 + 0x20] // value - push [esp + 0x18 + 0x20] // value - - mov ebx, 0x647400 - call ebx - add esp, 0x14 - - popad - - retn - } - } - - constexpr auto Dvar_SetFromStringFromSource_Func = 0x648580; - __declspec(naked) void Dvar_SetFromStringFromSource(const dvar_t* /*dvar*/, const char* /*string*/, DvarSetSource /*source*/) - { - __asm - { - pushad - - mov esi, [esp + 0x20 + 0x4] // dvar - mov eax, [esp + 0x20 + 0x8] // string - push [esp + 0x20 + 0xC] // source - call Dvar_SetFromStringFromSource_Func - add esp, 0x4 - - popad - - ret - } - } - constexpr auto ApplyTokenToField_Func = 0x59A760; __declspec(naked) bool ApplyTokenToField(unsigned int /*fieldNum*/, const char* /*token*/, visionSetVars_t* /*settings*/) { @@ -1754,19 +1247,26 @@ namespace Game } } - constexpr auto SV_BotUserMove_Addr = 0x626E50; - __declspec(naked) void SV_BotUserMove(client_t* /*client*/) + int SEH_GetLocalizedTokenReference(char* token, const char* reference, const char* messageType, msgLocErrType_t errType) { + static DWORD SEH_GetLocalizedTokenReference_t = 0x629BB0; + auto answer = 0; + __asm { pushad - - mov edi, [esp + 0x20 + 0x4] - call SV_BotUserMove_Addr - + mov esi, reference + mov edi, messageType + mov ebx, errType + push token + call SEH_GetLocalizedTokenReference_t + add esp, 0x4 + mov answer, eax popad - ret } + + return answer; } + #pragma optimize("", on) } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 35986f50..3fb14c97 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -1,1159 +1,640 @@ #pragma once +// Unsorted function definitions namespace Game { - template static void DB_ConvertOffsetToPointer(T* pointer) - { - Utils::Hook::Call(0x4A82B0)(pointer); - } - template static T** DB_InsertPointer() - { - static auto DB_InsertPointer_Address = 0x43B290; - T** retval = nullptr; - - __asm - { - call DB_InsertPointer_Address; - mov retval, eax; - } - - return retval; - } - - std::vector Sys_ListFilesWrapper(const std::string& directory, const std::string& extension); - - typedef void(__cdecl * AddRefToObject_t)(unsigned int id); - extern AddRefToObject_t AddRefToObject; - - typedef unsigned int(__cdecl * AllocObject_t)(); - extern AllocObject_t AllocObject; - - typedef void(__cdecl * AddRefToValue_t)(int type, VariableUnion u); - extern AddRefToValue_t AddRefToValue; - - typedef unsigned int(__cdecl * AllocThread_t)(unsigned int self); - extern AllocThread_t AllocThread; - - typedef unsigned int(__cdecl * VM_Execute_0_t)(unsigned int localId, const char* pos, unsigned int paramcount); - extern VM_Execute_0_t VM_Execute_0; - - typedef void(__cdecl * AngleVectors_t)(float *angles, float *forward, float *right, float *up); + typedef void(*AngleVectors_t)(float* angles, float* forward, float* right, float* up); extern AngleVectors_t AngleVectors; - typedef unsigned int(__cdecl * BG_GetNumWeapons_t)(); - extern BG_GetNumWeapons_t BG_GetNumWeapons; + typedef void(*Cbuf_AddServerText_f_t)(); + extern Cbuf_AddServerText_f_t Cbuf_AddServerText_f; - typedef const char*(__cdecl * BG_GetWeaponName_t)(unsigned int index); - extern BG_GetWeaponName_t BG_GetWeaponName; - - typedef void*(__cdecl * BG_LoadWeaponDef_LoadObj_t)(const char* name); - extern BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj; - - typedef WeaponCompleteDef*(__cdecl * BG_LoadWeaponCompleteDefInternal_t)(const char* folder, const char* name); - extern BG_LoadWeaponCompleteDefInternal_t BG_LoadWeaponCompleteDefInternal; - - typedef WeaponDef*(__cdecl * BG_GetWeaponDef_t)(unsigned int weaponIndex); - extern BG_GetWeaponDef_t BG_GetWeaponDef; - - typedef const char*(__cdecl * BG_GetEntityTypeName_t)(const int eType); - extern BG_GetEntityTypeName_t BG_GetEntityTypeName; - - typedef void(__cdecl * Cbuf_AddServerText_t)(); - extern Cbuf_AddServerText_t Cbuf_AddServerText; - - typedef void(__cdecl * Cbuf_AddText_t)(int localClientNum, const char* text); + typedef void(*Cbuf_AddText_t)(int localClientNum, const char* text); extern Cbuf_AddText_t Cbuf_AddText; - typedef void(__cdecl * Cbuf_InsertText_t)(int localClientNum, const char* text); + typedef void(*Cbuf_InsertText_t)(int localClientNum, const char* text); extern Cbuf_InsertText_t Cbuf_InsertText; - typedef int(__cdecl * CG_GetClientNum_t)(); + typedef int(*CG_GetClientNum_t)(); extern CG_GetClientNum_t CG_GetClientNum; - typedef void(__cdecl * CG_NextWeapon_f_t)(); + typedef void(*CG_NextWeapon_f_t)(); extern CG_NextWeapon_f_t CG_NextWeapon_f; - typedef std::int32_t(__cdecl * CG_PlayBoltedEffect_t) (std::int32_t, FxEffectDef*, std::int32_t, std::uint32_t); + typedef void(*CG_PlayBoltedEffect_t)(int localClientNum, FxEffectDef* fxDef, int dobjHandle, unsigned int boneName); extern CG_PlayBoltedEffect_t CG_PlayBoltedEffect; - typedef std::int32_t(__cdecl * CG_GetBoneIndex_t)(std::int32_t, std::uint32_t name, char* index); + typedef const DObj*(*CG_GetBoneIndex_t)(int localClientNum, unsigned int boneName, char* boneIndex); extern CG_GetBoneIndex_t CG_GetBoneIndex; - typedef void(__cdecl * CG_ScoresDown_f_t)(); + typedef void(*CG_ScoresDown_f_t)(); extern CG_ScoresDown_f_t CG_ScoresDown_f; - typedef void(__cdecl * CG_ScoresUp_f_t)(); + typedef void(*CG_ScoresUp_f_t)(); extern CG_ScoresUp_f_t CG_ScoresUp_f; - typedef void(__cdecl * CG_ScrollScoreboardUp_t)(cg_s* cgameGlob); + typedef void(*CG_ScrollScoreboardUp_t)(cg_s* cgameGlob); extern CG_ScrollScoreboardUp_t CG_ScrollScoreboardUp; - typedef void(__cdecl * CG_ScrollScoreboardDown_t)(cg_s* cgameGlob); + typedef void(*CG_ScrollScoreboardDown_t)(cg_s* cgameGlob); extern CG_ScrollScoreboardDown_t CG_ScrollScoreboardDown; - typedef const char*(__cdecl * CG_GetTeamName_t)(team_t team); + typedef const char*(*CG_GetTeamName_t)(team_t team); extern CG_GetTeamName_t CG_GetTeamName; - typedef void(__cdecl * CG_SetupWeaponDef_t)(int localClientNum, unsigned int weapIndex); + typedef void(*CG_SetupWeaponDef_t)(int localClientNum, unsigned int weapIndex); extern CG_SetupWeaponDef_t CG_SetupWeaponDef; - typedef int(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, int size); - extern CL_GetClientName_t CL_GetClientName; - - typedef int(__cdecl * CL_IsCgameInitialized_t)(); - extern CL_IsCgameInitialized_t CL_IsCgameInitialized; - - typedef void(__cdecl * CL_ConnectFromParty_t)(int controllerIndex, _XSESSION_INFO *hostInfo, netadr_t addr, int numPublicSlots, int numPrivateSlots, const char *mapname, const char *gametype); - extern CL_ConnectFromParty_t CL_ConnectFromParty; - - typedef void(__cdecl * CL_DownloadsComplete_t)(int controller); - extern CL_DownloadsComplete_t CL_DownloadsComplete; - - typedef void(_cdecl * CL_DrawStretchPicPhysical_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material); - extern CL_DrawStretchPicPhysical_t CL_DrawStretchPicPhysical; - - typedef const char*(_cdecl* CL_GetConfigString_t)(int index); - extern CL_GetConfigString_t CL_GetConfigString; - - typedef int(_cdecl* CL_GetMaxRank_t)(); - extern CL_GetMaxRank_t CL_GetMaxRank; - - typedef int(_cdecl* CL_GetRankForXP_t)(int xp); - extern CL_GetRankForXP_t CL_GetRankForXP; - - typedef void(__cdecl * CL_GetRankIcon_t)(int level, int prestige, Material** material); - extern CL_GetRankIcon_t CL_GetRankIcon; - - typedef void(__cdecl * CL_HandleRelayPacket_t)(Game::msg_t* msg, int client); - extern CL_HandleRelayPacket_t CL_HandleRelayPacket; - - typedef void(__cdecl * CL_ResetViewport_t)(); - extern CL_ResetViewport_t CL_ResetViewport; - - typedef void(__cdecl * CL_SelectStringTableEntryInDvar_f_t)(); - extern CL_SelectStringTableEntryInDvar_f_t CL_SelectStringTableEntryInDvar_f; - - typedef void(__cdecl * CL_DrawStretchPic_t)(const ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, float s1, float t1, float s2, float t2, const float* color, Material* material); - extern CL_DrawStretchPic_t CL_DrawStretchPic; - - typedef void(__cdecl * CL_ConsoleFixPosition_t)(); - extern CL_ConsoleFixPosition_t CL_ConsoleFixPosition; - - typedef int(__cdecl * CL_GetLocalClientActiveCount_t)(); - extern CL_GetLocalClientActiveCount_t CL_GetLocalClientActiveCount; - - typedef int(__cdecl * CL_ControllerIndexFromClientNum_t)(int localActiveClientNum); - extern CL_ControllerIndexFromClientNum_t CL_ControllerIndexFromClientNum; - - typedef void(__cdecl * Cmd_AddCommand_t)(const char* cmdName, void(*function), cmd_function_t* allocedCmd, bool isKey); + typedef void(*Cmd_AddCommand_t)(const char* cmdName, void(*function), cmd_function_t* allocedCmd, bool isKey); extern Cmd_AddCommand_t Cmd_AddCommand; - typedef void(__cdecl * Cmd_AddServerCommand_t)(const char* name, void(*callback), cmd_function_t* data); + typedef void(*Cmd_AddServerCommand_t)(const char* name, void(*callback), cmd_function_t* data); extern Cmd_AddServerCommand_t Cmd_AddServerCommand; - typedef void(__cdecl * Cmd_ExecuteSingleCommand_t)(int localClientNum, int controllerIndex, const char* cmd); + typedef void(*Cmd_ExecuteSingleCommand_t)(int localClientNum, int controllerIndex, const char* cmd); extern Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand; - typedef void(__cdecl * Com_ClientPacketEvent_t)(); + typedef void(*Com_ClientPacketEvent_t)(); extern Com_ClientPacketEvent_t Com_ClientPacketEvent; - typedef void(__cdecl * Com_Error_t)(errorParm_t type, const char* message, ...); + typedef void(*Com_Error_t)(errorParm_t type, const char* message, ...); extern Com_Error_t Com_Error; - typedef void(__cdecl * Com_Printf_t)(int channel, const char* fmt, ...); + typedef void(*Com_Printf_t)(int channel, const char* fmt, ...); extern Com_Printf_t Com_Printf; - typedef void(__cdecl * Com_PrintError_t)(int channel, const char* fmt, ...); + typedef void(*Com_PrintError_t)(int channel, const char* fmt, ...); extern Com_PrintError_t Com_PrintError; - typedef void(__cdecl * Com_PrintWarning_t)(int channel, const char* fmt, ...); + typedef void(*Com_PrintWarning_t)(int channel, const char* fmt, ...); extern Com_PrintWarning_t Com_PrintWarning; - typedef void(__cdecl * Com_PrintMessage_t)(int channel, const char* msg, int error); + typedef void(*Com_PrintMessage_t)(int channel, const char* msg, int error); extern Com_PrintMessage_t Com_PrintMessage; - typedef void(__cdecl * Com_EndParseSession_t)(); + typedef void(*Com_EndParseSession_t)(); extern Com_EndParseSession_t Com_EndParseSession; - typedef void(__cdecl * Com_BeginParseSession_t)(const char* filename); + typedef void(*Com_BeginParseSession_t)(const char* filename); extern Com_BeginParseSession_t Com_BeginParseSession; - typedef char*(__cdecl * Com_ParseOnLine_t)(const char** data_p); + typedef char*(*Com_ParseOnLine_t)(const char** data_p); extern Com_ParseOnLine_t Com_ParseOnLine; - typedef void(__cdecl * Com_SkipRestOfLine_t)(const char** data); + typedef void(*Com_SkipRestOfLine_t)(const char** data); extern Com_SkipRestOfLine_t Com_SkipRestOfLine; - typedef void(__cdecl * Com_SetSpaceDelimited_t)(int); + typedef void(*Com_SetSpaceDelimited_t)(int); extern Com_SetSpaceDelimited_t Com_SetSpaceDelimited; - typedef char*(__cdecl * Com_Parse_t)(const char** data_p); + typedef char*(*Com_Parse_t)(const char** data_p); extern Com_Parse_t Com_Parse; - typedef bool (__cdecl * Com_MatchToken_t)(const char **data_p, const char* token, int size); + typedef bool (*Com_MatchToken_t)(const char **data_p, const char* token, int size); extern Com_MatchToken_t Com_MatchToken; - typedef void(__cdecl * Com_SetSlowMotion_t)(float start, float end, int duration); + typedef void(*Com_SetSlowMotion_t)(float start, float end, int duration); extern Com_SetSlowMotion_t Com_SetSlowMotion; - typedef void(__cdecl * Com_Quitf_t)(); + typedef void(*Com_Quitf_t)(); extern Com_Quitf_t Com_Quit_f; - typedef char* (__cdecl * Con_DrawMiniConsole_t)(int localClientNum, int xPos, int yPos, float alpha); + typedef void(*Com_OpenLogFile_t)(); + extern Com_OpenLogFile_t Com_OpenLogFile; + + typedef char* (*Con_DrawMiniConsole_t)(int localClientNum, int xPos, int yPos, float alpha); extern Con_DrawMiniConsole_t Con_DrawMiniConsole; - typedef void (__cdecl * Con_DrawSolidConsole_t)(); + typedef void (*Con_DrawSolidConsole_t)(); extern Con_DrawSolidConsole_t Con_DrawSolidConsole; - typedef bool(__cdecl * Con_CancelAutoComplete_t)(); + typedef bool(*Con_CancelAutoComplete_t)(); extern Con_CancelAutoComplete_t Con_CancelAutoComplete; - typedef char *(__cdecl *DB_AllocStreamPos_t)(int alignment); - extern DB_AllocStreamPos_t DB_AllocStreamPos; - - typedef void(__cdecl * DB_PushStreamPos_t)(unsigned int index); - extern DB_PushStreamPos_t DB_PushStreamPos; - - typedef void(__cdecl * DB_PopStreamPos_t)(); - extern DB_PopStreamPos_t DB_PopStreamPos; - - typedef void(__cdecl * DB_BeginRecoverLostDevice_t)(); - extern DB_BeginRecoverLostDevice_t DB_BeginRecoverLostDevice; - - typedef void(__cdecl * DB_EndRecoverLostDevice_t)(); - extern DB_EndRecoverLostDevice_t DB_EndRecoverLostDevice; - - typedef void(__cdecl * DB_EnumXAssets_t)(XAssetType type, void(*)(XAssetHeader, void *), void* userdata, bool overrides); - extern DB_EnumXAssets_t DB_EnumXAssets; - - typedef void(__cdecl * DB_EnumXAssets_Internal_t)(XAssetType type, void(*)(XAssetHeader, void *), void* userdata, bool overrides); - extern DB_EnumXAssets_Internal_t DB_EnumXAssets_Internal; - - typedef XAssetHeader (__cdecl * DB_FindXAssetHeader_t)(XAssetType type, const char* name); - extern DB_FindXAssetHeader_t DB_FindXAssetHeader; - - typedef float(__cdecl * DB_GetLoadedFraction_t)(); - extern DB_GetLoadedFraction_t DB_GetLoadedFraction; - - typedef const char* (__cdecl * DB_GetXAssetNameHandler_t)(XAssetHeader* asset); - extern DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers; - - typedef int(__cdecl * DB_GetXAssetSizeHandler_t)(); - extern DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers; - - typedef const char *(__cdecl * DB_GetXAssetTypeName_t)(XAssetType type); - extern DB_GetXAssetTypeName_t DB_GetXAssetTypeName; - - typedef int(__cdecl * DB_IsXAssetDefault_t)(XAssetType type, const char* name); - extern DB_IsXAssetDefault_t DB_IsXAssetDefault; - - typedef void(__cdecl * DB_GetRawBuffer_t)(RawFile* rawfile, char* buffer, int size); - extern DB_GetRawBuffer_t DB_GetRawBuffer; - - typedef int(__cdecl * DB_GetRawFileLen_t)(RawFile* rawfile); - extern DB_GetRawFileLen_t DB_GetRawFileLen; - - typedef void(*DB_LoadXAssets_t)(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); - extern DB_LoadXAssets_t DB_LoadXAssets; - - typedef void(*DB_LoadXFileData_t)(char *pos, int size); - extern DB_LoadXFileData_t DB_LoadXFileData; - - typedef void(__cdecl * DB_ReadXFileUncompressed_t)(void* buffer, int size); - extern DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed; - - typedef void(__cdecl * DB_ReadXFile_t)(void* buffer, int size); - extern DB_ReadXFile_t DB_ReadXFile; - - typedef void(__cdecl * DB_ReleaseXAssetHandler_t)(XAssetHeader header); - extern DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers; - - typedef void(__cdecl * DB_SetXAssetName_t)(XAsset* asset, const char* name); - extern DB_SetXAssetName_t DB_SetXAssetName; - - typedef void(__cdecl * DB_SetXAssetNameHandler_t)(XAssetHeader* header, const char* name); - extern DB_SetXAssetNameHandler_t* DB_SetXAssetNameHandlers; - - typedef void(__cdecl * DB_XModelSurfsFixup_t)(XModel* model); - extern DB_XModelSurfsFixup_t DB_XModelSurfsFixup; - - typedef dvar_t*(__cdecl * Dvar_RegisterBool_t)(const char* dvarName, bool value, unsigned __int16 flags, const char* description); - extern Dvar_RegisterBool_t Dvar_RegisterBool; - - typedef dvar_t*(__cdecl * Dvar_RegisterFloat_t)(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description); - extern Dvar_RegisterFloat_t Dvar_RegisterFloat; - - typedef dvar_t*(__cdecl * Dvar_RegisterVec2_t)(const char* dvarName, float x, float y, float min, float max, unsigned __int16 flags, const char* description); - extern Dvar_RegisterVec2_t Dvar_RegisterVec2; - - typedef dvar_t*(__cdecl * Dvar_RegisterVec3_t)(const char* dvarName, float x, float y, float z, float min, float max, unsigned __int16 flags, const char* description); - extern Dvar_RegisterVec3_t Dvar_RegisterVec3; - - typedef dvar_t*(__cdecl * Dvar_RegisterVec4_t)(const char* dvarName, float x, float y, float z, float w, float min, float max, unsigned __int16 flags, const char* description); - extern Dvar_RegisterVec4_t Dvar_RegisterVec4; - - typedef dvar_t*(__cdecl * Dvar_RegisterInt_t)(const char* dvarName, int value, int min, int max, unsigned __int16 flags, const char* description); - extern Dvar_RegisterInt_t Dvar_RegisterInt; - - typedef dvar_t*(__cdecl * Dvar_RegisterEnum_t)(const char* dvarName, const char** valueList, int defaultIndex, unsigned __int16 flags, const char* description); - extern Dvar_RegisterEnum_t Dvar_RegisterEnum; - - typedef dvar_t*(__cdecl * Dvar_RegisterString_t)(const char* dvarName, const char* value, unsigned __int16 flags, const char* description); - extern Dvar_RegisterString_t Dvar_RegisterString; - - typedef dvar_t*(__cdecl * Dvar_RegisterColor_t)(const char* dvarName, float r, float g, float b, float a, unsigned __int16 flags, const char* description); - extern Dvar_RegisterColor_t Dvar_RegisterColor; - - typedef dvar_t*(__cdecl * Dvar_RegisterVec3Color_t)(const char* dvarName, float x, float y, float z, float max, unsigned __int16 flags, const char* description); - extern Dvar_RegisterVec3Color_t Dvar_RegisterVec3Color; - - typedef void(__cdecl * Dvar_SetFromStringByName_t)(const char* dvarName, const char* string); - extern Dvar_SetFromStringByName_t Dvar_SetFromStringByName; - - typedef const dvar_t*(__cdecl * Dvar_SetFromStringByNameFromSource_t)(const char* dvarName, const char* string, DvarSetSource source); - extern Dvar_SetFromStringByNameFromSource_t Dvar_SetFromStringByNameFromSource; - - typedef void(__cdecl * Dvar_SetStringByName_t)(const char* dvarName, const char* value); - extern Dvar_SetStringByName_t Dvar_SetStringByName; - - typedef void(__cdecl * Dvar_SetString_t)(const dvar_t* dvar, const char* value); - extern Dvar_SetString_t Dvar_SetString; - - typedef void(__cdecl * Dvar_SetBool_t)(const dvar_t* dvar, bool enabled); - extern Dvar_SetBool_t Dvar_SetBool; - - typedef void(__cdecl * Dvar_SetFloat_t)(const dvar_t* dvar, float value); - extern Dvar_SetFloat_t Dvar_SetFloat; - - typedef void(__cdecl * Dvar_SetInt_t)(const dvar_t* dvar, int integer); - extern Dvar_SetInt_t Dvar_SetInt; - - typedef void(__cdecl * Dvar_GetUnpackedColorByName_t)(const char* dvarName, float* expandedColor); - extern Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName; - - typedef char*(__cdecl* Dvar_GetString_t)(const char* dvarName); - extern Dvar_GetString_t Dvar_GetString; - - typedef char*(__cdecl * Dvar_GetVariantString_t)(const char* dvarName); - extern Dvar_GetVariantString_t Dvar_GetVariantString; - - typedef dvar_t*(__cdecl * Dvar_FindVar_t)(const char* dvarName); - extern Dvar_FindVar_t Dvar_FindVar; - - typedef char*(__cdecl * Dvar_InfoString_Big_t)(int bit); - extern Dvar_InfoString_Big_t Dvar_InfoString_Big; - - typedef void(__cdecl * Dvar_SetCommand_t)(const char* dvarName, const char* string); - extern Dvar_SetCommand_t Dvar_SetCommand; - - typedef const char*(__cdecl * Dvar_DisplayableValue_t)(const dvar_t* dvar); - extern Dvar_DisplayableValue_t Dvar_DisplayableValue; - - typedef void(__cdecl * Dvar_Reset_t)(const dvar_t* dvar, DvarSetSource setSource); - extern Dvar_Reset_t Dvar_Reset; - - typedef bool(__cdecl * Encode_Init_t)(const char* ); + typedef bool(*Encode_Init_t)(const char* ); extern Encode_Init_t Encode_Init; - typedef void(__cdecl * Field_Clear_t)(void* field); + typedef void(*Field_Clear_t)(void* field); extern Field_Clear_t Field_Clear; - typedef void(__cdecl * FreeMemory_t)(void* buffer); + typedef void(*FreeMemory_t)(void* buffer); extern FreeMemory_t FreeMemory; - typedef void (__cdecl * Free_String_t)(const char* string); + typedef void(*Free_String_t)(const char* string); extern Free_String_t Free_String; - typedef void(__cdecl * FS_FreeFile_t)(void* buffer); - extern FS_FreeFile_t FS_FreeFile; - - typedef int(__cdecl * FS_ReadFile_t)(const char* path, char** buffer); - extern FS_ReadFile_t FS_ReadFile; - - typedef char** (__cdecl * FS_GetFileList_t)(const char *path, const char *extension, FsListBehavior_e behavior, int *numfiles, int allocTrackType); - extern FS_GetFileList_t FS_GetFileList; - - typedef void(__cdecl * FS_FreeFileList_t)(char** list); - extern FS_FreeFileList_t FS_FreeFileList; - - typedef int(__cdecl * FS_FOpenFileAppend_t)(const char* file); - extern FS_FOpenFileAppend_t FS_FOpenFileAppend; - extern FS_FOpenFileAppend_t FS_FOpenFileWrite; - - typedef int(__cdecl * FS_FOpenFileRead_t)(const char* file, int* fh/*, int uniqueFile*/); - extern FS_FOpenFileRead_t FS_FOpenFileRead; - - typedef int(__cdecl * FS_FOpenFileReadForThread_t)(const char *filename, int *file, int thread); - extern FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread; - - typedef int(__cdecl * FS_FCloseFile_t)(int stream); - extern FS_FCloseFile_t FS_FCloseFile; - - typedef bool(__cdecl * FS_FileExists_t)(const char* file); - extern FS_FileExists_t FS_FileExists; - - typedef bool(__cdecl * FS_WriteFile_t)(const char* filename, const char* folder, const void* buffer, int size); - extern FS_WriteFile_t FS_WriteFile; - - typedef int(__cdecl * FS_WriteToDemo_t)(const void* buffer, int size, int file); - extern FS_WriteToDemo_t FS_WriteToDemo; - - typedef int(__cdecl * FS_Write_t)(const void* buffer, int len, int h); - extern FS_Write_t FS_Write; - - typedef int(__cdecl * FS_Printf_t)(int file, const char* fmt, ...); - extern FS_Printf_t FS_Printf; - - typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file); - extern FS_Read_t FS_Read; - - typedef int(__cdecl * FS_Seek_t)(int fileHandle, int seekPosition, int seekOrigin); - extern FS_Seek_t FS_Seek; - - typedef int(__cdecl * FS_FTell_t)(int fileHandle); - extern FS_FTell_t FS_FTell; - - typedef int(__cdecl * FS_Remove_t)(char *); - extern FS_Remove_t FS_Remove; - - typedef int(__cdecl * FS_Restart_t)(int localClientNum, int checksumFeed); - extern FS_Restart_t FS_Restart; - - typedef int(__cdecl * FS_BuildPathToFile_t)(const char*, const char*, const char*, char**); - extern FS_BuildPathToFile_t FS_BuildPathToFile; - - typedef iwd_t*(__cdecl * FS_IsShippedIWD_t)(const char* fullpath, const char* iwd); - extern FS_IsShippedIWD_t FS_IsShippedIWD; - - typedef int(__cdecl* FS_Delete_t)(const char* fileName); - extern FS_Delete_t FS_Delete; - - typedef void(__cdecl * G_LogPrintf_t)(const char* fmt, ...); - extern G_LogPrintf_t G_LogPrintf; - - typedef unsigned int(__cdecl * G_GetWeaponIndexForName_t)(const char*); - extern G_GetWeaponIndexForName_t G_GetWeaponIndexForName; - - typedef void(__cdecl * G_SpawnEntitiesFromString_t)(); - extern G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString; - - typedef gentity_s*(__cdecl * G_Spawn_t)(); - extern G_Spawn_t G_Spawn; - - typedef void(__cdecl * G_FreeEntity_t)(gentity_s* ed); - extern G_FreeEntity_t G_FreeEntity; - - typedef void(__cdecl * G_SpawnItem_t)(gentity_s* ent, int item); - extern G_SpawnItem_t G_SpawnItem; - - typedef void(__cdecl * G_GetItemClassname_t)(int item, gentity_s* ent); - extern G_GetItemClassname_t G_GetItemClassname; - - typedef void(__cdecl * G_PrintEntities_t)(); - extern G_PrintEntities_t G_PrintEntities; - - typedef const char*(__cdecl * G_GetEntityTypeName_t)(const gentity_s* ent); - extern G_GetEntityTypeName_t G_GetEntityTypeName; - - typedef void(__cdecl * Svcmd_EntityList_f_t)(); + typedef void(*Svcmd_EntityList_f_t)(); extern Svcmd_EntityList_f_t Svcmd_EntityList_f; - typedef void(__cdecl * GScr_LoadGameTypeScript_t)(); + typedef void(*GScr_LoadGameTypeScript_t)(); extern GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript; - typedef int(__cdecl * Reader_t)(char const*, int *); - typedef bool(__cdecl * Image_LoadFromFileWithReader_t)(GfxImage* image, Reader_t reader); + typedef int(*Reader_t)(char const*, int *); + + typedef bool(*Image_LoadFromFileWithReader_t)(GfxImage* image, Reader_t reader); extern Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader; - typedef void(__cdecl * Image_Release_t)(GfxImage* image); + typedef void(*Image_Release_t)(GfxImage* image); extern Image_Release_t Image_Release; - typedef char*(__cdecl * Info_ValueForKey_t)(const char* s, const char* key); + typedef char*(*Info_ValueForKey_t)(const char* s, const char* key); extern Info_ValueForKey_t Info_ValueForKey; - typedef void(__cdecl * Key_SetCatcher_t)(int localClientNum, int catcher); + typedef void(*Key_SetCatcher_t)(int localClientNum, int catcher); extern Key_SetCatcher_t Key_SetCatcher; - typedef void(__cdecl * Key_RemoveCatcher_t)(int localClientNum, int andMask); + typedef void(*Key_RemoveCatcher_t)(int localClientNum, int andMask); extern Key_RemoveCatcher_t Key_RemoveCatcher; - typedef bool(__cdecl * Key_IsKeyCatcherActive_t)(int localClientNum, int catcher); + typedef bool(*Key_IsKeyCatcherActive_t)(int localClientNum, int catcher); extern Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive; - typedef void(__cdecl * Key_SetBinding_t)(int localClientNum, int keyNum, const char* binding); + typedef void(*Key_SetBinding_t)(int localClientNum, int keyNum, const char* binding); extern Key_SetBinding_t Key_SetBinding; - typedef void(__cdecl * LargeLocalInit_t)(); + typedef void(*LargeLocalInit_t)(); extern LargeLocalInit_t LargeLocalInit; - typedef bool(__cdecl * Load_Stream_t)(bool atStreamStart, const void* ptr, unsigned int size); + typedef bool(*Load_Stream_t)(bool atStreamStart, const void* ptr, unsigned int size); extern Load_Stream_t Load_Stream; - typedef void(__cdecl * Load_XString_t)(bool atStreamStart); + typedef void(*Load_XString_t)(bool atStreamStart); extern Load_XString_t Load_XString; - typedef void(__cdecl * Load_XModelPtr_t)(bool atStreamStart); + typedef void(*Load_XModelPtr_t)(bool atStreamStart); extern Load_XModelPtr_t Load_XModelPtr; - typedef void(__cdecl * Load_XModelSurfsFixup_t)(XModelSurfs**, XModelLodInfo*); + typedef void(*Load_XModelSurfsFixup_t)(XModelSurfs**, XModelLodInfo*); extern Load_XModelSurfsFixup_t Load_XModelSurfsFixup; - typedef void(__cdecl * Load_XStringArray_t)(bool atStreamStart, int count); + typedef void(*Load_XStringArray_t)(bool atStreamStart, int count); extern Load_XStringArray_t Load_XStringArray; - typedef void(__cdecl * Load_XStringCustom_t)(const char** str); + typedef void(*Load_XStringCustom_t)(const char** str); extern Load_XStringCustom_t Load_XStringCustom; - typedef void(__cdecl * Load_FxEffectDefHandle_t)(bool atStreamStart); + typedef void(*Load_FxEffectDefHandle_t)(bool atStreamStart); extern Load_FxEffectDefHandle_t Load_FxEffectDefHandle; - typedef void(__cdecl * Load_FxElemDef_t)(bool atStreamStart); + typedef void(*Load_FxElemDef_t)(bool atStreamStart); extern Load_FxElemDef_t Load_FxElemDef; - typedef void(__cdecl * Load_GfxImagePtr_t)(bool atStreamStart); + typedef void(*Load_GfxImagePtr_t)(bool atStreamStart); extern Load_GfxImagePtr_t Load_GfxImagePtr; - typedef void(__cdecl * Load_GfxTextureLoad_t)(bool atStreamStart); + typedef void(*Load_GfxTextureLoad_t)(bool atStreamStart); extern Load_GfxTextureLoad_t Load_GfxTextureLoad; - typedef int(__cdecl * Load_Texture_t)(GfxImageLoadDef** loadDef, GfxImage* image); + typedef int(*Load_Texture_t)(GfxImageLoadDef** loadDef, GfxImage* image); extern Load_Texture_t Load_Texture; - typedef void(__cdecl * Load_SndAliasCustom_t)(snd_alias_list_t** var); + typedef void(*Load_SndAliasCustom_t)(snd_alias_list_t** var); extern Load_SndAliasCustom_t Load_SndAliasCustom; - typedef void(__cdecl * Load_MaterialHandle_t)(bool atStreamStart); + typedef void(*Load_MaterialHandle_t)(bool atStreamStart); extern Load_MaterialHandle_t Load_MaterialHandle; - typedef void(__cdecl * Load_PhysCollmapPtr_t)(bool atStreamStart); + typedef void(*Load_PhysCollmapPtr_t)(bool atStreamStart); extern Load_PhysCollmapPtr_t Load_PhysCollmapPtr; - typedef void(__cdecl * Load_PhysPresetPtr_t)(bool atStreamStart); + typedef void(*Load_PhysPresetPtr_t)(bool atStreamStart); extern Load_PhysPresetPtr_t Load_PhysPresetPtr; - typedef void(__cdecl * Load_TracerDefPtr_t)(bool atStreamStart); + typedef void(*Load_TracerDefPtr_t)(bool atStreamStart); extern Load_TracerDefPtr_t Load_TracerDefPtr; - typedef void(__cdecl * Load_snd_alias_list_nameArray_t)(bool atStreamStart, int count); + typedef void(*Load_snd_alias_list_nameArray_t)(bool atStreamStart, int count); extern Load_snd_alias_list_nameArray_t Load_snd_alias_list_nameArray; - typedef void(__cdecl * Menus_CloseAll_t)(UiContext* dc); + typedef void(*Menus_CloseAll_t)(UiContext* dc); extern Menus_CloseAll_t Menus_CloseAll; - typedef void(__cdecl * Menus_CloseRequest_t)(UiContext* dc, menuDef_t* menu); + typedef void(*Menus_CloseRequest_t)(UiContext* dc, menuDef_t* menu); extern Menus_CloseRequest_t Menus_CloseRequest; - typedef int(__cdecl * Menus_OpenByName_t)(UiContext* dc, const char* p); + typedef int(*Menus_OpenByName_t)(UiContext* dc, const char* p); extern Menus_OpenByName_t Menus_OpenByName; - typedef menuDef_t *(__cdecl * Menus_FindByName_t)(UiContext* dc, const char* name); + typedef menuDef_t *(*Menus_FindByName_t)(UiContext* dc, const char* name); extern Menus_FindByName_t Menus_FindByName; - typedef bool(__cdecl * Menu_IsVisible_t)(UiContext* dc, menuDef_t* menu); + typedef bool(*Menu_IsVisible_t)(UiContext* dc, menuDef_t* menu); extern Menu_IsVisible_t Menu_IsVisible; - typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext* dc, menuDef_t* menu); + typedef bool(*Menus_MenuIsInStack_t)(UiContext* dc, menuDef_t* menu); extern Menus_MenuIsInStack_t Menus_MenuIsInStack; - typedef menuDef_t*(__cdecl * Menu_GetFocused_t)(UiContext* ctx); + typedef menuDef_t*(*Menu_GetFocused_t)(UiContext* ctx); extern Menu_GetFocused_t Menu_GetFocused; - typedef void(__cdecl * Menu_HandleKey_t)(UiContext* ctx, menuDef_t* menu, Game::keyNum_t key, int down); + typedef void(*Menu_HandleKey_t)(UiContext* ctx, menuDef_t* menu, Game::keyNum_t key, int down); extern Menu_HandleKey_t Menu_HandleKey; - typedef bool(__cdecl * UI_KeyEvent_t)(int clientNum, int key, int down); + typedef bool(*UI_KeyEvent_t)(int clientNum, int key, int down); extern UI_KeyEvent_t UI_KeyEvent; - typedef const char*(__cdecl * UI_SafeTranslateString_t)(const char* reference); + typedef const char*(*UI_SafeTranslateString_t)(const char* reference); extern UI_SafeTranslateString_t UI_SafeTranslateString; - typedef void(__cdecl * UI_ReplaceConversions_t)(const char* sourceString, ConversionArguments* arguments, char* outputString, size_t outputStringSize); + typedef void(*UI_ReplaceConversions_t)(const char* sourceString, ConversionArguments* arguments, char* outputString, size_t outputStringSize); extern UI_ReplaceConversions_t UI_ReplaceConversions; + + typedef int(*UI_ParseInfos_t)(const char* buf, int max, char** infos); + extern UI_ParseInfos_t UI_ParseInfos; - typedef void(__cdecl * MSG_Init_t)(msg_t* buf, char* data, int length); + typedef void(*MSG_Init_t)(msg_t* buf, unsigned char* data, int length); extern MSG_Init_t MSG_Init; - typedef void(__cdecl * MSG_ReadData_t)(msg_t* msg, void* data, int len); + typedef void(*MSG_ReadData_t)(msg_t* msg, void* data, int len); extern MSG_ReadData_t MSG_ReadData; - typedef int(__cdecl * MSG_ReadLong_t)(msg_t* msg); + typedef int(*MSG_ReadLong_t)(msg_t* msg); extern MSG_ReadLong_t MSG_ReadLong; - typedef int(__cdecl * MSG_ReadBit_t)(msg_t* msg); + typedef int(*MSG_ReadBit_t)(msg_t* msg); extern MSG_ReadBit_t MSG_ReadBit; - typedef int(__cdecl * MSG_ReadBits_t)(msg_t* msg, int bits); + typedef int(*MSG_ReadBits_t)(msg_t* msg, int bits); extern MSG_ReadBits_t MSG_ReadBits; - typedef short(__cdecl * MSG_ReadShort_t)(msg_t* msg); + typedef int(*MSG_ReadShort_t)(msg_t* msg); extern MSG_ReadShort_t MSG_ReadShort; - typedef __int64(__cdecl * MSG_ReadInt64_t)(msg_t* msg); + typedef __int64(*MSG_ReadInt64_t)(msg_t* msg); extern MSG_ReadInt64_t MSG_ReadInt64; - typedef char* (__cdecl * MSG_ReadString_t)(msg_t* msg); + typedef char* (*MSG_ReadString_t)(msg_t* msg); extern MSG_ReadString_t MSG_ReadString; - typedef char* (__cdecl * MSG_ReadStringLine_t)(msg_t *msg, char *string, unsigned int maxChars); + typedef char* (*MSG_ReadStringLine_t)(msg_t *msg, char *string, unsigned int maxChars); extern MSG_ReadStringLine_t MSG_ReadStringLine; - typedef int(__cdecl * MSG_ReadByte_t)(msg_t* msg); + typedef int(*MSG_ReadByte_t)(msg_t* msg); extern MSG_ReadByte_t MSG_ReadByte; - typedef int(__cdecl * MSG_ReadBitsCompress_t)(const char *from, char *to, int size); + typedef int(*MSG_ReadBitsCompress_t)(const char *from, char *to, int size); extern MSG_ReadBitsCompress_t MSG_ReadBitsCompress; - typedef void(__cdecl * MSG_WriteByte_t)(msg_t* msg, unsigned char c); + typedef void(*MSG_WriteByte_t)(msg_t* msg, int c); extern MSG_WriteByte_t MSG_WriteByte; - typedef void(__cdecl * MSG_WriteData_t)(msg_t *buf, const void *data, int length); + typedef void(*MSG_WriteData_t)(msg_t *buf, const void *data, int length); extern MSG_WriteData_t MSG_WriteData; - typedef void(__cdecl * MSG_WriteLong_t)(msg_t *msg, int c); + typedef void(*MSG_WriteLong_t)(msg_t *msg, int c); extern MSG_WriteLong_t MSG_WriteLong; - typedef void(__cdecl * MSG_WriteShort_t)(msg_t* msg, short s); + typedef void(*MSG_WriteShort_t)(msg_t* msg, int s); extern MSG_WriteShort_t MSG_WriteShort; - typedef void(__cdecl * MSG_WriteString_t)(msg_t* msg, const char *str); + typedef void(*MSG_WriteString_t)(msg_t* msg, const char *str); extern MSG_WriteString_t MSG_WriteString; - typedef int(__cdecl * MSG_WriteBitsCompress_t)(bool trainHuffman, const char *from, char *to, int size); + typedef bool(*MSG_ReadDeltaUsercmdKey_t)(msg_t* msg, int key, const usercmd_s* from, usercmd_s* to); + extern MSG_ReadDeltaUsercmdKey_t MSG_ReadDeltaUsercmdKey; + + typedef int(*MSG_WriteBitsCompress_t)(bool trainHuffman, const char *from, char *to, int size); extern MSG_WriteBitsCompress_t MSG_WriteBitsCompress; - typedef void(__cdecl * NetadrToSockadr_t)(netadr_t *a, sockaddr *s); + typedef void(*NetadrToSockadr_t)(netadr_t *a, sockaddr *s); extern NetadrToSockadr_t NetadrToSockadr; - typedef const char* (__cdecl * NET_AdrToString_t)(netadr_t adr); + typedef const char* (*NET_AdrToString_t)(netadr_t adr); extern NET_AdrToString_t NET_AdrToString; - typedef bool(__cdecl * NET_CompareAdr_t)(netadr_t a, netadr_t b); + typedef bool(*NET_CompareAdr_t)(netadr_t a, netadr_t b); extern NET_CompareAdr_t NET_CompareAdr; - typedef void(__cdecl * NET_DeferPacketToClient_t)(netadr_t *, msg_t *); + typedef void(*NET_DeferPacketToClient_t)(netadr_t *, msg_t *); extern NET_DeferPacketToClient_t NET_DeferPacketToClient; - typedef const char* (__cdecl * NET_ErrorString_t)(); + typedef const char* (*NET_ErrorString_t)(); extern NET_ErrorString_t NET_ErrorString; - typedef void(__cdecl * NET_Init_t)(); + typedef void(*NET_Init_t)(); extern NET_Init_t NET_Init; - typedef bool(__cdecl * NET_IsLocalAddress_t)(netadr_t adr); + typedef bool(*NET_IsLocalAddress_t)(netadr_t adr); extern NET_IsLocalAddress_t NET_IsLocalAddress; - typedef int(__cdecl * NET_StringToAdr_t)(const char *s, netadr_t *a); + typedef int(*NET_StringToAdr_t)(const char *s, netadr_t *a); extern NET_StringToAdr_t NET_StringToAdr; - typedef void(__cdecl * NET_OutOfBandPrint_t)(netsrc_t sock, netadr_t adr, const char *data); + typedef void(*NET_OutOfBandPrint_t)(netsrc_t sock, netadr_t adr, const char *data); extern NET_OutOfBandPrint_t NET_OutOfBandPrint; - typedef void(__cdecl * NET_OutOfBandData_t)(netsrc_t sock, netadr_t adr, const char *format, int len); + typedef void(*NET_OutOfBandData_t)(netsrc_t sock, netadr_t adr, const char *format, int len); extern NET_OutOfBandData_t NET_OutOfBandData; - typedef void(__cdecl * Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite); + typedef int(*NET_OutOfBandVoiceData_t)(netsrc_t sock, netadr_t adr, unsigned char* format, int len, bool voiceData); + extern NET_OutOfBandVoiceData_t NET_OutOfBandVoiceData; + + typedef void(*Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite); extern Live_MPAcceptInvite_t Live_MPAcceptInvite; - typedef int(__cdecl * Live_GetMapIndex_t)(const char* mapname); + typedef int(*Live_GetMapIndex_t)(const char* mapname); extern Live_GetMapIndex_t Live_GetMapIndex; - typedef int(__cdecl * Live_GetPrestige_t)(int controllerIndex); + typedef int(*Live_GetPrestige_t)(int controllerIndex); extern Live_GetPrestige_t Live_GetPrestige; - typedef int(__cdecl * Live_GetXp_t)(int controllerIndex); + typedef int(*Live_GetXp_t)(int controllerIndex); extern Live_GetXp_t Live_GetXp; - typedef int(__cdecl * LiveStorage_GetStat_t)(int controllerIndex, int index); + typedef const char*(*Live_GetLocalClientName_t)(int controllerIndex); + extern Live_GetLocalClientName_t Live_GetLocalClientName; + + typedef int(*LiveStorage_GetStat_t)(int controllerIndex, int index); extern LiveStorage_GetStat_t LiveStorage_GetStat; - typedef char*(__cdecl * Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive); + typedef char*(*Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive); extern Scr_AddSourceBuffer_t Scr_AddSourceBuffer; - typedef int(__cdecl * PC_ReadToken_t)(source_t*, token_t*); + typedef int(*PC_ReadToken_t)(source_t*, token_t*); extern PC_ReadToken_t PC_ReadToken; - typedef int(__cdecl * PC_ReadTokenHandle_t)(int handle, pc_token_s *pc_token); + typedef int(*PC_ReadTokenHandle_t)(int handle, pc_token_s *pc_token); extern PC_ReadTokenHandle_t PC_ReadTokenHandle; - typedef void(__cdecl * PC_SourceError_t)(int, const char*, ...); + typedef void(*PC_SourceError_t)(int, const char*, ...); extern PC_SourceError_t PC_SourceError; - typedef int(__cdecl * Party_GetMaxPlayers_t)(PartyData* party); + typedef int(*Party_GetMaxPlayers_t)(PartyData* party); extern Party_GetMaxPlayers_t Party_GetMaxPlayers; - typedef int(__cdecl * PartyHost_CountMembers_t)(PartyData* party); + typedef int(*PartyHost_CountMembers_t)(PartyData* party); extern PartyHost_CountMembers_t PartyHost_CountMembers; - typedef netadr_t *(__cdecl * PartyHost_GetMemberAddressBySlot_t)(int unk, void *party, const int slot); + typedef netadr_t *(*PartyHost_GetMemberAddressBySlot_t)(int unk, void *party, const int slot); extern PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot; - typedef const char *(__cdecl * PartyHost_GetMemberName_t)(PartyData* party, const int clientNum); + typedef const char *(*PartyHost_GetMemberName_t)(PartyData* party, const int clientNum); extern PartyHost_GetMemberName_t PartyHost_GetMemberName; - typedef void(__cdecl * Playlist_ParsePlaylists_t)(const char* data); + typedef int(*Party_InParty_t)(PartyData* party); + extern Party_InParty_t Party_InParty; + + typedef void(*Playlist_ParsePlaylists_t)(const char* data); extern Playlist_ParsePlaylists_t Playlist_ParsePlaylists; - typedef Font_s*(__cdecl * R_RegisterFont_t)(const char* asset, int safe); + typedef Font_s*(*R_RegisterFont_t)(const char* asset, int safe); extern R_RegisterFont_t R_RegisterFont; - typedef void(__cdecl * R_AddCmdDrawText_t)(const char *text, int maxChars, Font_s *font, float x, float y, float xScale, float yScale, float rotation, const float *color, int style); + typedef void(*R_AddCmdDrawText_t)(const char *text, int maxChars, Font_s *font, float x, float y, float xScale, float yScale, float rotation, const float *color, int style); extern R_AddCmdDrawText_t R_AddCmdDrawText; - typedef void(_cdecl * R_AddCmdDrawStretchPic_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material); + typedef void(*R_AddCmdDrawStretchPic_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material); extern R_AddCmdDrawStretchPic_t R_AddCmdDrawStretchPic; - typedef void* (__cdecl * R_AllocStaticIndexBuffer_t)(IDirect3DIndexBuffer9** store, int length); + typedef void*(*R_AllocStaticIndexBuffer_t)(IDirect3DIndexBuffer9** store, int length); extern R_AllocStaticIndexBuffer_t R_AllocStaticIndexBuffer; - typedef bool(__cdecl * R_Cinematic_StartPlayback_Now_t)(); + typedef bool(*R_Cinematic_StartPlayback_Now_t)(); extern R_Cinematic_StartPlayback_Now_t R_Cinematic_StartPlayback_Now; - typedef void(__cdecl * R_LoadGraphicsAssets_t)(); + typedef void(*R_LoadGraphicsAssets_t)(); extern R_LoadGraphicsAssets_t R_LoadGraphicsAssets; - typedef int(__cdecl * R_TextWidth_t)(const char* text, int maxlength, Font_s* font); + typedef int(*R_TextWidth_t)(const char* text, int maxlength, Font_s* font); extern R_TextWidth_t R_TextWidth; - typedef int(__cdecl * R_TextHeight_t)(Font_s* font); + typedef int(*R_TextHeight_t)(Font_s* font); extern R_TextHeight_t R_TextHeight; - typedef void(__cdecl * R_FlushSun_t)(); + typedef void(*R_FlushSun_t)(); extern R_FlushSun_t R_FlushSun; - typedef GfxWorld*(__cdecl * R_SortWorldSurfaces_t)(); + typedef GfxWorld*(*R_SortWorldSurfaces_t)(); extern R_SortWorldSurfaces_t R_SortWorldSurfaces; - typedef void(__cdecl * RemoveRefToObject_t)(unsigned int id); - extern RemoveRefToObject_t RemoveRefToObject; - - typedef void(__cdecl * Scr_AddEntity_t)(const gentity_s* ent); - extern Scr_AddEntity_t Scr_AddEntity; - - typedef void(__cdecl * Scr_AddString_t)(const char* value); - extern Scr_AddString_t Scr_AddString; - - typedef void(__cdecl * Scr_AddConstString_t)(unsigned int value); - extern Scr_AddConstString_t Scr_AddConstString; - - typedef void(__cdecl * Scr_AddIString_t)(const char* value); - extern Scr_AddIString_t Scr_AddIString; - - typedef void(__cdecl * Scr_AddInt_t)(int value); - extern Scr_AddInt_t Scr_AddInt; - - typedef void(__cdecl * Scr_AddFloat_t)(float value); - extern Scr_AddFloat_t Scr_AddFloat; - - typedef void(__cdecl * Scr_AddObject_t)(unsigned int id); - extern Scr_AddObject_t Scr_AddObject; - - typedef void(__cdecl * Scr_ShutdownAllocNode_t)(); - extern Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode; - - typedef void(__cdecl * Scr_LoadGameType_t)(); - extern Scr_LoadGameType_t Scr_LoadGameType; - - typedef void(__cdecl * Scr_StartupGameType_t)(); - extern Scr_StartupGameType_t Scr_StartupGameType; - - typedef int(__cdecl * Scr_LoadScript_t)(const char*); - extern Scr_LoadScript_t Scr_LoadScript; - - typedef const char*(__cdecl * Scr_GetString_t)(unsigned int index); - extern Scr_GetString_t Scr_GetString; - - typedef scr_string_t(__cdecl * Scr_GetConstString_t)(unsigned int index); - extern Scr_GetConstString_t Scr_GetConstString; - - typedef const char*(__cdecl * Scr_GetDebugString_t)(unsigned int index); - extern Scr_GetDebugString_t Scr_GetDebugString; - - typedef float(__cdecl * Scr_GetFloat_t)(unsigned int index); - extern Scr_GetFloat_t Scr_GetFloat; - - typedef int(__cdecl * Scr_GetInt_t)(unsigned int index); - extern Scr_GetInt_t Scr_GetInt; - - typedef unsigned int(__cdecl * Scr_GetObject_t)(unsigned int index); - extern Scr_GetObject_t Scr_GetObject; - - typedef unsigned int(__cdecl * Scr_GetNumParam_t)(); - extern Scr_GetNumParam_t Scr_GetNumParam; - - typedef unsigned int(__cdecl * Scr_GetEntityId_t)(int entnum, unsigned int classnum); - extern Scr_GetEntityId_t Scr_GetEntityId; - - typedef int(__cdecl * Scr_GetFunctionHandle_t)(const char* filename, const char* name); - extern Scr_GetFunctionHandle_t Scr_GetFunctionHandle; - - typedef int(__cdecl * Scr_ExecThread_t)(int handle, unsigned int paramcount); - extern Scr_ExecThread_t Scr_ExecThread; - - typedef int(__cdecl * Scr_ExecEntThread_t)(gentity_s* ent, int handle, unsigned int paramcount); - extern Scr_ExecEntThread_t Scr_ExecEntThread; - - typedef void(__cdecl * Scr_FreeThread_t)(unsigned __int16 handle); - extern Scr_FreeThread_t Scr_FreeThread; - - typedef void(__cdecl * Scr_Notify_t)(gentity_t *ent, unsigned __int16 stringValue, unsigned int paramcount); - extern Scr_Notify_t Scr_Notify; - - typedef void(__cdecl * Scr_NotifyLevel_t)(unsigned __int16 stringValue, unsigned int paramcount); - extern Scr_NotifyLevel_t Scr_NotifyLevel; - - typedef void(__cdecl * Scr_ClearOutParams_t)(); - extern Scr_ClearOutParams_t Scr_ClearOutParams; - - typedef void(__cdecl * Scr_RegisterFunction_t)(int func, const char* name); - extern Scr_RegisterFunction_t Scr_RegisterFunction; - - typedef bool(__cdecl * Scr_IsSystemActive_t)(); - extern Scr_IsSystemActive_t Scr_IsSystemActive; - - typedef int(__cdecl * Scr_GetType_t)(unsigned int index); - extern Scr_GetType_t Scr_GetType; - - typedef int(__cdecl * Scr_GetPointerType_t)(unsigned int index); - extern Scr_GetPointerType_t Scr_GetPointerType; - - typedef void(__cdecl * Scr_Error_t)(const char*); - extern Scr_Error_t Scr_Error; - - typedef void(__cdecl * Scr_ObjectError_t)(const char*); - extern Scr_ObjectError_t Scr_ObjectError; - - typedef void(__cdecl * Scr_ParamError_t)(unsigned int paramIndex, const char*); - extern Scr_ParamError_t Scr_ParamError; - - typedef void(__cdecl * Scr_GetObjectField_t)(unsigned int classnum, int entnum, int offset); - extern Scr_GetObjectField_t Scr_GetObjectField; - - typedef int(__cdecl * Scr_SetObjectField_t)(unsigned int classnum, int entnum, int offset); - extern Scr_SetObjectField_t Scr_SetObjectField; - - typedef void(__cdecl * Scr_SetClientField_t)(gclient_s* client, int offset); - extern Scr_SetClientField_t Scr_SetClientField; - - typedef void(__cdecl * Scr_GetEntityField_t)(int entnum, int offset); - extern Scr_GetEntityField_t Scr_GetEntityField; - - typedef void(__cdecl * Scr_AddClassField_t)(unsigned int classnum, const char* name, unsigned int offset); - extern Scr_AddClassField_t Scr_AddClassField; - - typedef gentity_s*(__cdecl * GetPlayerEntity_t)(scr_entref_t entref); - extern GetPlayerEntity_t GetPlayerEntity; - - typedef gentity_s*(__cdecl * GetEntity_t)(scr_entref_t entref); - extern GetEntity_t GetEntity; - - typedef script_t* (__cdecl * Script_Alloc_t)(int length); + typedef script_t*(*Script_Alloc_t)(int length); extern Script_Alloc_t Script_Alloc; - typedef void(__cdecl * Script_SetupTokens_t)(script_t* script, void* tokens); + typedef void(*Script_SetupTokens_t)(script_t* script, void* tokens); extern Script_SetupTokens_t Script_SetupTokens; - typedef int(__cdecl * Script_CleanString_t)(char* buffer); + typedef int(*Script_CleanString_t)(char* buffer); extern Script_CleanString_t Script_CleanString; - typedef char*(__cdecl * SE_Load_t)(const char* file, int Unk); + typedef char*(*SE_Load_t)(const char* file, int Unk); extern SE_Load_t SE_Load; - typedef char*(__cdecl * SEH_StringEd_GetString_t)(const char* string); + typedef char*(*SEH_StringEd_GetString_t)(const char* string); extern SEH_StringEd_GetString_t SEH_StringEd_GetString; - typedef unsigned int(__cdecl * SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); + typedef unsigned int(*SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); extern SEH_ReadCharFromString_t SEH_ReadCharFromString; - typedef int (__cdecl * SEH_GetCurrentLanguage_t)(); + typedef int(*SEH_GetCurrentLanguage_t)(); extern SEH_GetCurrentLanguage_t SEH_GetCurrentLanguage; - typedef const char*(__cdecl * SL_ConvertToString_t)(scr_string_t stringValue); + typedef const char*(*SL_ConvertToString_t)(scr_string_t stringValue); extern SL_ConvertToString_t SL_ConvertToString; - typedef short(__cdecl * SL_GetString_t)(const char *str, unsigned int user); + typedef short(*SL_GetString_t)(const char *str, unsigned int user); extern SL_GetString_t SL_GetString; - typedef void(__cdecl * SL_AddRefToString_t)(unsigned int stringValue); + typedef void(*SL_AddRefToString_t)(unsigned int stringValue); extern SL_AddRefToString_t SL_AddRefToString; - typedef void(__cdecl * SL_RemoveRefToString_t)(unsigned int stringValue); + typedef void(*SL_RemoveRefToString_t)(unsigned int stringValue); extern SL_RemoveRefToString_t SL_RemoveRefToString; - typedef void(__cdecl * SND_Init_t)(int a1, int a2, int a3); + typedef void(*SND_Init_t)(int a1, int a2, int a3); extern SND_Init_t SND_Init; - typedef void(__cdecl * SND_InitDriver_t)(); + typedef void(*SND_InitDriver_t)(); extern SND_InitDriver_t SND_InitDriver; - typedef void(__cdecl * SockadrToNetadr_t)(sockaddr *s, netadr_t *a); + typedef void(*SockadrToNetadr_t)(sockaddr *s, netadr_t *a); extern SockadrToNetadr_t SockadrToNetadr; - typedef void(__cdecl * Steam_JoinLobby_t)(SteamID, char); + typedef void(*Steam_JoinLobby_t)(SteamID, char); extern Steam_JoinLobby_t Steam_JoinLobby; - typedef const char*(__cdecl * StringTable_Lookup_t)(const StringTable *table, const int comparisonColumn, const char *value, const int valueColumn); + typedef const char*(*StringTable_Lookup_t)(const StringTable *table, const int comparisonColumn, const char *value, const int valueColumn); extern StringTable_Lookup_t StringTable_Lookup; - typedef const char* (__cdecl * StringTable_GetColumnValueForRow_t)(const StringTable* table, int, int column); + typedef const char* (*StringTable_GetColumnValueForRow_t)(const StringTable* table, int, int column); extern StringTable_GetColumnValueForRow_t StringTable_GetColumnValueForRow; - typedef int(__cdecl * StringTable_HashString_t)(const char* string); + typedef int(*StringTable_HashString_t)(const char* string); extern StringTable_HashString_t StringTable_HashString; - typedef gentity_t*(__cdecl* SV_AddTestClient_t)(); - extern SV_AddTestClient_t SV_AddTestClient; - - typedef int(__cdecl * SV_IsTestClient_t)(int clientNum); - extern SV_IsTestClient_t SV_IsTestClient; - - typedef int(__cdecl* SV_GameClientNum_Score_t)(int clientID); - extern SV_GameClientNum_Score_t SV_GameClientNum_Score; - - typedef void(__cdecl * SV_GameSendServerCommand_t)(int clientNum, svscmd_type type, const char* text); - extern SV_GameSendServerCommand_t SV_GameSendServerCommand; - - typedef void(__cdecl * SV_Cmd_TokenizeString_t)(const char* string); - extern SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString; - - typedef void(__cdecl * SV_Cmd_EndTokenizedString_t)(); - extern SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString; - - typedef void(__cdecl * SV_Cmd_ArgvBuffer_t)(int arg, char* buf, int size); - extern SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer; - - typedef void(__cdecl * SV_SetConfigstring_t)(int index, const char* string); - extern SV_SetConfigstring_t SV_SetConfigstring; - - typedef void(__cdecl * SV_DirectConnect_t)(netadr_t adr); - extern SV_DirectConnect_t SV_DirectConnect; - - typedef bool(__cdecl * SV_Loaded_t)(); - extern SV_Loaded_t SV_Loaded; - - typedef void(__cdecl * SV_ClientThink_t)(client_s*, usercmd_s*); - extern SV_ClientThink_t SV_ClientThink; - - typedef void(__cdecl * SV_DropClient_t)(client_t* drop, const char* reason, bool tellThem); - extern SV_DropClient_t SV_DropClient; - - typedef client_t*(__cdecl * SV_GetPlayerByName_t)(); - extern SV_GetPlayerByName_t SV_GetPlayerByName; - - typedef client_t*(__cdecl * SV_GetPlayerByNum_t)(); - extern SV_GetPlayerByNum_t SV_GetPlayerByNum; - - typedef void(__cdecl * Sys_Error_t)(const char* error, ...); - extern Sys_Error_t Sys_Error; - - typedef void(__cdecl * Sys_FreeFileList_t)(char** list); - extern Sys_FreeFileList_t Sys_FreeFileList; - - typedef int(__cdecl * Sys_IsDatabaseReady_t)(); - extern Sys_IsDatabaseReady_t Sys_IsDatabaseReady; - - typedef int(__cdecl * Sys_IsDatabaseReady2_t)(); - extern Sys_IsDatabaseReady2_t Sys_IsDatabaseReady2; - - typedef bool(__cdecl * Sys_IsMainThread_t)(); - extern Sys_IsMainThread_t Sys_IsMainThread; - - typedef bool(__cdecl * Sys_IsRenderThread_t)(); - extern Sys_IsRenderThread_t Sys_IsRenderThread; - - typedef bool(__cdecl * Sys_IsServerThread_t)(); - extern Sys_IsServerThread_t Sys_IsServerThread; - - typedef bool(__cdecl * Sys_IsDatabaseThread_t)(); - extern Sys_IsDatabaseThread_t Sys_IsDatabaseThread; - - typedef char**(__cdecl * Sys_ListFiles_t)(const char* directory, const char* extension, const char* filter, int* numfiles, int wantsubs); - extern Sys_ListFiles_t Sys_ListFiles; - - typedef int(__cdecl * Sys_Milliseconds_t)(); - extern Sys_Milliseconds_t Sys_Milliseconds; - - typedef void(__cdecl * Sys_LockWrite_t)(FastCriticalSection* critSect); - extern Sys_LockWrite_t Sys_LockWrite; - - typedef void(__cdecl * Sys_TempPriorityAtLeastNormalBegin_t)(TempPriority*); - extern Sys_TempPriorityAtLeastNormalBegin_t Sys_TempPriorityAtLeastNormalBegin; - - typedef void(__cdecl * Sys_TempPriorityEnd_t)(TempPriority*); - extern Sys_TempPriorityEnd_t Sys_TempPriorityEnd; - - typedef void(__cdecl * TeleportPlayer_t)(gentity_t* entity, float* pos, float* orientation); + typedef void(*TeleportPlayer_t)(gentity_t* entity, float* pos, float* orientation); extern TeleportPlayer_t TeleportPlayer; - typedef bool(__cdecl * Sys_SendPacket_t)(netsrc_t sock, size_t len, const char *format, netadr_t adr); - extern Sys_SendPacket_t Sys_SendPacket; - - typedef void(__cdecl * Sys_ShowConsole_t)(); - extern Sys_ShowConsole_t Sys_ShowConsole; - - typedef void(__cdecl * Sys_SuspendOtherThreads_t)(); - extern Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads; - - typedef void(__cdecl * UI_AddMenuList_t)(UiContext* dc, MenuList* menuList, int close); + typedef void(*UI_AddMenuList_t)(UiContext* dc, MenuList* menuList, int close); extern UI_AddMenuList_t UI_AddMenuList; - typedef uiMenuCommand_t(__cdecl * UI_GetActiveMenu_t)(int localClientNum); + typedef uiMenuCommand_t(*UI_GetActiveMenu_t)(int localClientNum); extern UI_GetActiveMenu_t UI_GetActiveMenu; - typedef char*(__cdecl * UI_CheckStringTranslation_t)(char*, char*); + typedef char*(*UI_CheckStringTranslation_t)(char*, char*); extern UI_CheckStringTranslation_t UI_CheckStringTranslation; - typedef MenuList*(__cdecl * UI_LoadMenus_t)(const char* menuFile, int imageTrack); + typedef MenuList*(*UI_LoadMenus_t)(const char* menuFile, int imageTrack); extern UI_LoadMenus_t UI_LoadMenus; - typedef void(__cdecl * UI_UpdateArenas_t)(); + typedef void(*UI_UpdateArenas_t)(); extern UI_UpdateArenas_t UI_UpdateArenas; - typedef void(__cdecl * UI_SortArenas_t)(); + typedef void(*UI_SortArenas_t)(); extern UI_SortArenas_t UI_SortArenas; - typedef void(__cdecl * UI_DrawHandlePic_t)(ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Material* material); + typedef void(*UI_DrawHandlePic_t)(ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Material* material); extern UI_DrawHandlePic_t UI_DrawHandlePic; - typedef ScreenPlacement*(__cdecl * ScrPlace_GetActivePlacement_t)(int localClientNum); + typedef ScreenPlacement*(*ScrPlace_GetActivePlacement_t)(int localClientNum); extern ScrPlace_GetActivePlacement_t ScrPlace_GetActivePlacement; - typedef int(__cdecl * UI_TextWidth_t)(const char* text, int maxChars, Font_s* font, float scale); + typedef int(*UI_TextWidth_t)(const char* text, int maxChars, Font_s* font, float scale); extern UI_TextWidth_t UI_TextWidth; - typedef int(__cdecl * UI_TextHeight_t)(Font_s* font, float scale); + typedef int(*UI_TextHeight_t)(Font_s* font, float scale); extern UI_TextHeight_t UI_TextHeight; - typedef void(__cdecl * UI_DrawText_t)(const ScreenPlacement* scrPlace, const char* text, int maxChars, Font_s* font, float x, float y, int horzAlign, int vertAlign, float scale, const float* color, int style); + typedef void(*UI_DrawText_t)(const ScreenPlacement* scrPlace, const char* text, int maxChars, Font_s* font, float x, float y, int horzAlign, int vertAlign, float scale, const float* color, int style); extern UI_DrawText_t UI_DrawText; - typedef Font_s* (__cdecl* UI_GetFontHandle_t)(ScreenPlacement* scrPlace, int fontEnum, float scale); + typedef Font_s*(*UI_GetFontHandle_t)(ScreenPlacement* scrPlace, int fontEnum, float scale); extern UI_GetFontHandle_t UI_GetFontHandle; - typedef void(__cdecl* ScrPlace_ApplyRect_t)(const ScreenPlacement* scrPlace, float* x, float* y, float* w, float* h, int horzAlign, int vertAlign); + typedef void(*ScrPlace_ApplyRect_t)(const ScreenPlacement* scrPlace, float* x, float* y, float* w, float* h, int horzAlign, int vertAlign); extern ScrPlace_ApplyRect_t ScrPlace_ApplyRect; - typedef const char*(__cdecl * Win_GetLanguage_t)(); + typedef const char*(*Win_GetLanguage_t)(); extern Win_GetLanguage_t Win_GetLanguage; - typedef void(__cdecl * Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t*); + typedef void(*Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t*); extern Vec3UnpackUnitVec_t Vec3UnpackUnitVec; - typedef float(__cdecl * vectoyaw_t)(vec2_t* vec); + typedef float(*vectoyaw_t)(vec2_t* vec); extern vectoyaw_t vectoyaw; - typedef float(__cdecl * AngleNormalize360_t)(float val); + typedef float(*AngleNormalize360_t)(float val); extern AngleNormalize360_t AngleNormalize360; - typedef void(__cdecl * unzClose_t)(void* handle); + typedef void(*unzClose_t)(void* handle); extern unzClose_t unzClose; - typedef void(__cdecl* RB_DrawCursor_t)(Material* material, char cursor, float x, float y, float sinAngle, float cosAngle, Font_s* font, float xScale, float yScale, unsigned int color); + typedef void(*RB_DrawCursor_t)(Material* material, char cursor, float x, float y, float sinAngle, float cosAngle, Font_s* font, float xScale, float yScale, unsigned int color); extern RB_DrawCursor_t RB_DrawCursor; - typedef float(__cdecl* R_NormalizedTextScale_t)(Font_s* font, float scale); + typedef float(*R_NormalizedTextScale_t)(Font_s* font, float scale); extern R_NormalizedTextScale_t R_NormalizedTextScale; - typedef void(__cdecl * Material_Process2DTextureCoordsForAtlasing_t)(const Material* material, float* s0, float* s1, float* t0, float* t1); + typedef void(*Material_Process2DTextureCoordsForAtlasing_t)(const Material* material, float* s0, float* s1, float* t0, float* t1); extern Material_Process2DTextureCoordsForAtlasing_t Material_Process2DTextureCoordsForAtlasing; - typedef void(__cdecl* Byte4PackRgba_t)(const float* from, char* to); + typedef void(*Byte4PackRgba_t)(const float* from, char* to); extern Byte4PackRgba_t Byte4PackRgba; - typedef int(__cdecl* RandWithSeed_t)(int* seed); + typedef int(*RandWithSeed_t)(int* seed); extern RandWithSeed_t RandWithSeed; - typedef void(__cdecl* GetDecayingLetterInfo_t)(unsigned int letter, int* randSeed, int decayTimeElapsed, int fxBirthTime, int fxDecayDuration, unsigned __int8 alpha, bool* resultSkipDrawing, char* resultAlpha, unsigned int* resultLetter, bool* resultDrawExtraFxChar); + typedef void(*GetDecayingLetterInfo_t)(unsigned int letter, int* randSeed, int decayTimeElapsed, int fxBirthTime, int fxDecayDuration, unsigned __int8 alpha, bool* resultSkipDrawing, char* resultAlpha, unsigned int* resultLetter, bool* resultDrawExtraFxChar); extern GetDecayingLetterInfo_t GetDecayingLetterInfo; - typedef void(__cdecl * Field_Draw_t)(int localClientNum, field_t* edit, int x, int y, int horzAlign, int vertAlign); + typedef void(*Field_Draw_t)(int localClientNum, field_t* edit, int x, int y, int horzAlign, int vertAlign); extern Field_Draw_t Field_Draw; - typedef void(__cdecl * Field_AdjustScroll_t)(ScreenPlacement* scrPlace, field_t* edit); + typedef void(*Field_AdjustScroll_t)(ScreenPlacement* scrPlace, field_t* edit); extern Field_AdjustScroll_t Field_AdjustScroll; - typedef void(__cdecl * AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); + typedef void(*AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); extern AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee; - typedef gentity_s*(__cdecl * Weapon_RocketLauncher_Fire_t)(gentity_s* ent, unsigned int weaponIndex, float spread, weaponParms* wp, const float* gunVel, lockonFireParms* lockParms, bool a7); + typedef gentity_s*(*Weapon_RocketLauncher_Fire_t)(gentity_s* ent, unsigned int weaponIndex, float spread, weaponParms* wp, const float* gunVel, lockonFireParms* lockParms, bool magicBullet); extern Weapon_RocketLauncher_Fire_t Weapon_RocketLauncher_Fire; - typedef void(__cdecl * Jump_ClearState_t)(playerState_s* ps); + typedef void(*Jump_ClearState_t)(playerState_s* ps); extern Jump_ClearState_t Jump_ClearState; - typedef void(__cdecl * PM_playerTrace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask); + typedef void(*PM_playerTrace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask); extern PM_playerTrace_t PM_playerTrace; - typedef void(__cdecl * PM_Trace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask); + typedef void(*PM_Trace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask); extern PM_Trace_t PM_Trace; - typedef EffectiveStance(__cdecl * PM_GetEffectiveStance_t)(const playerState_s* ps); + typedef EffectiveStance(*PM_GetEffectiveStance_t)(const playerState_s* ps); extern PM_GetEffectiveStance_t PM_GetEffectiveStance; - typedef int(__cdecl * CL_MouseEvent_t)(int x, int y, int dx, int dy); - extern CL_MouseEvent_t CL_MouseEvent; + typedef void(*PM_UpdateLean_t)(playerState_s* ps, float msec, usercmd_s* cmd, void(*capsuleTrace)(trace_t*, const float*, const float*, const Bounds*, int, int)); + extern PM_UpdateLean_t PM_UpdateLean; - typedef void(__cdecl * IN_RecenterMouse_t)(); + typedef void(*IN_RecenterMouse_t)(); extern IN_RecenterMouse_t IN_RecenterMouse; - typedef void(__cdecl * IN_MouseMove_t)(); + typedef void(*IN_MouseMove_t)(); extern IN_MouseMove_t IN_MouseMove; - typedef void(__cdecl * IN_Init_t)(); + typedef void(*IN_Init_t)(); extern IN_Init_t IN_Init; - typedef void(__cdecl * IN_Shutdown_t)(); + typedef void(*IN_Shutdown_t)(); extern IN_Shutdown_t IN_Shutdown; - typedef void(__cdecl * Touch_Item_t)(gentity_s* ent, gentity_s* other, int touched); + typedef void(*Touch_Item_t)(gentity_s* ent, gentity_s* other, int touched); extern Touch_Item_t Touch_Item; - typedef void(__cdecl * Add_Ammo_t)(gentity_s* ent, unsigned int weaponIndex, unsigned char weaponModel, int count, int fillClip); + typedef void(*Add_Ammo_t)(gentity_s* ent, unsigned int weaponIndex, unsigned char weaponModel, int count, int fillClip); extern Add_Ammo_t Add_Ammo; - typedef void(__cdecl * ClientUserinfoChanged_t)(int clientNum); + typedef void(*ClientUserinfoChanged_t)(int clientNum); extern ClientUserinfoChanged_t ClientUserinfoChanged; - typedef void(__cdecl * player_die_t)(gentity_s* self, const gentity_s* inflictor, gentity_s* attacker, int damage, int meansOfDeath, int iWeapon, const float* vDir, const hitLocation_t hitLoc, int psTimeOffset); + typedef void(*player_die_t)(gentity_s* self, const gentity_s* inflictor, gentity_s* attacker, int damage, int meansOfDeath, int iWeapon, const float* vDir, const hitLocation_t hitLoc, int psTimeOffset); extern player_die_t player_die; - typedef float(__cdecl * Vec3Normalize_t)(float* v); + typedef float(*Vec3Normalize_t)(float* v); extern Vec3Normalize_t Vec3Normalize; - typedef void(__cdecl * Vec3NormalizeFast_t)(float* v); + typedef void(*Vec3NormalizeFast_t)(float* v); extern Vec3NormalizeFast_t Vec3NormalizeFast; - typedef float(__cdecl * Vec2Normalize_t)(float* v); + typedef float(*Vec2Normalize_t)(float* v); extern Vec2Normalize_t Vec2Normalize; - typedef void(__cdecl * Vec2NormalizeFast_t)(float* v); + typedef void(*Vec2NormalizeFast_t)(float* v); extern Vec2NormalizeFast_t Vec2NormalizeFast; - typedef void*(__cdecl * Z_VirtualAlloc_t)(int size); + typedef void*(*Z_VirtualAlloc_t)(int size); extern Z_VirtualAlloc_t Z_VirtualAlloc; - typedef void(__cdecl * I_strncpyz_t)(char* dest, const char* src, int destsize); + typedef void(*I_strncpyz_t)(char* dest, const char* src, int destsize); extern I_strncpyz_t I_strncpyz; + typedef char*(*I_CleanStr_t)(char* string); + extern I_CleanStr_t I_CleanStr; + + typedef void(*XNAddrToString_t)(const XNADDR* xnaddr, char* str); + extern XNAddrToString_t XNAddrToString; + + typedef int(*Voice_IncomingVoiceData_t)(const SessionData* session, int clientNum, unsigned char* data, int size); + extern Voice_IncomingVoiceData_t Voice_IncomingVoiceData; + + typedef bool(*Voice_IsClientTalking_t)(int clientNum); + extern Voice_IsClientTalking_t Voice_IsClientTalking; + + typedef int(*LargeLocalBegin_t)(int size); + extern LargeLocalBegin_t LargeLocalBegin; + + typedef int(*LargeLocalBeginRight_t)(int size); + extern LargeLocalBeginRight_t LargeLocalBeginRight; + constexpr std::size_t STATIC_MAX_LOCAL_CLIENTS = 1; constexpr std::size_t MAX_LOCAL_CLIENTS = 1; constexpr std::size_t MAX_CLIENTS = 18; - extern XAssetHeader* DB_XAssetPool; - extern unsigned int* g_poolSize; - constexpr auto CMD_MAX_NESTING = 8; extern CmdArgs* cmd_args; extern CmdArgs* sv_cmd_args; extern cmd_function_t** cmd_functions; - extern float* cl_angles; extern float* cgameFOVSensitivityScale; - extern int* svs_time; - extern int* svs_clientCount; - extern client_t* svs_clients; - extern source_t **sourceFiles; extern keywordHash_t **menuParseKeywordHash; @@ -1165,16 +646,12 @@ namespace Game extern int* gameTypeCount; extern gameTypeName_t* gameTypes; - extern searchpath_t** fs_searchpaths; - - extern XBlock** g_streamBlocks; - extern int* g_streamPos; - extern int* g_streamPosIndex; - extern bool* g_lobbyCreateInProgress; extern PartyData* g_lobbyData; extern PartyData* g_partyData; + extern SessionData* g_serverSession; + extern int* numIP; extern netIP_t* localIP; @@ -1183,10 +660,6 @@ namespace Game extern int* demoRecording; extern int* serverMessageSequence; - constexpr std::size_t MAX_GENTITIES = 2048; - constexpr std::size_t ENTITYNUM_NONE = MAX_GENTITIES - 1; - extern gentity_t* g_entities; - extern netadr_t* connectedHost; extern SOCKET* ip_socket; @@ -1212,7 +685,7 @@ namespace Game extern FxEffectDef*** varFxEffectDefHandle; extern PhysCollmap*** varPhysCollmapPtr; extern PhysPreset*** varPhysPresetPtr; - extern Game::MaterialPass** varMaterialPass; + extern MaterialPass** varMaterialPass; extern snd_alias_list_t*** varsnd_alias_list_name; extern FxElemField* s_elemFields; @@ -1221,12 +694,6 @@ namespace Game extern infoParm_t* infoParams; - extern XZone* g_zones; - extern unsigned short* db_hashTable; - - extern scrVmPub_t* scrVmPub; - extern scrVarPub_t* scrVarPub; - extern clientState_t* clcState; extern GfxScene* scene; @@ -1238,9 +705,6 @@ namespace Game extern float* g_console_char_height; extern field_t* g_consoleField; - extern clientStatic_t* cls; - extern clientUIActive_t* clientUIActives; - extern sharedUiInfo_t* sharedUiInfo; extern ScreenPlacement* scrPlaceFull; extern ScreenPlacement* scrPlaceFullUnsafe; @@ -1270,8 +734,6 @@ namespace Game extern float (*CorrectSolidDeltas)[26][3]; - extern FastCriticalSection* db_hashCritSect; - extern level_locals_t* level; extern float (*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT]; @@ -1295,45 +757,37 @@ namespace Game extern int* com_errorPrintsCount; - extern scr_const_t* scr_const; - - extern clientConnection_t* clientConnections; - constexpr std::size_t PLAYER_CARD_UI_STRING_COUNT = 18; extern unsigned int* playerCardUIStringIndex; extern char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38]; + extern uiInfo_s* uiInfoArray; + + extern int* logfile; + extern GamerSettingState* gamerSettings; - void Sys_LockRead(FastCriticalSection* critSect); - void Sys_UnlockRead(FastCriticalSection* critSect); + extern unsigned char* g_largeLocalBuf; + extern int* g_largeLocalPos; + extern int* g_largeLocalRightPos; - XModel* G_GetModel(int index); + extern char** ui_arenaInfos; + extern int* ui_numArenas; + extern int* ui_arenaBufPos; ScreenPlacement* ScrPlace_GetFullPlacement(); ScreenPlacement* ScrPlace_GetUnsafeFullPlacement(); void UI_FilterStringForButtonAnimation(char* str, unsigned int strMaxSize); - XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize); - void Menu_FreeItemMemory(Game::itemDef_s* item); - void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1); - void Menu_SetPrevCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1); + void Menu_FreeItemMemory(itemDef_s* item); + void Menu_SetNextCursorItem(UiContext* ctx, menuDef_t* currentMenu, int unk = 1); + void Menu_SetPrevCursorItem(UiContext* ctx, menuDef_t* currentMenu, int unk = 1); const char* TableLookup(StringTable* stringtable, int row, int column); const char* UI_LocalizeMapName(const char* mapName); const char* UI_LocalizeGameType(const char* gameType); float UI_GetScoreboardLeft(void*); - const char *DB_GetXAssetName(XAsset *asset); - XAssetType DB_GetXAssetNameType(const char* name); - int DB_GetZoneIndex(const std::string& name); - bool DB_IsZoneLoaded(const char* zone); - void DB_EnumXAssetEntries(XAssetType type, std::function callback, bool overrides); - XAssetHeader DB_FindXAssetDefaultHeaderInternal(XAssetType type); - XAssetEntry* DB_FindXAssetEntry(XAssetType type, const char* name); - - void FS_AddLocalizedGameDirectory(const char *path, const char *dir); - bool PM_IsAdsAllowed(playerState_s* ps); void ShowMessageBox(const std::string& message, const std::string& title); @@ -1343,29 +797,15 @@ namespace Game void R_LoadSunThroughDvars(const char* mapname, sunflare_t* sun); void R_SetSunFromDvars(sunflare_t* sun); - void SV_GameDropClient(int clientNum, const char* reason); - void SV_DropAllBots(); - void SV_BotUserMove(client_t* client); - - void RuntimeErrorInternal(int channel, const char* codePos, unsigned int index, const char* msg); - void IncInParam(); - - void Scr_NotifyId(unsigned int id, unsigned __int16 stringValue, unsigned int paramcount); - void Scr_AddBool(int value); - void IN_KeyUp(kbutton_t* button); void IN_KeyDown(kbutton_t* button); - int FS_FOpenFileReadCurrentThread(const char* file, int* fh); - void Load_IndexBuffer(void* data, IDirect3DIndexBuffer9** storeHere, int count); void Load_VertexBuffer(void* data, IDirect3DVertexBuffer9** where, int len); char* Com_GetParseThreadInfo(); void Com_SetParseNegativeNumbers(int parse); - int CL_GetMaxXP(); - void Image_Setup(GfxImage* image, unsigned int width, unsigned int height, unsigned int depth, unsigned int flags, _D3DFORMAT format); void Vec2UnpackTexCoords(const PackedTexCoords in, vec2_t* out); @@ -1391,8 +831,10 @@ namespace Game void AimAssist_UpdateTweakables(int localClientNum); void AimAssist_UpdateAdsLerp(const AimInput* input); - void Dvar_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source); - void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source); - bool ApplyTokenToField(unsigned int fieldNum, const char* token, visionSetVars_t* settings); + + int SEH_GetLocalizedTokenReference(char* token, const char* reference, const char* messageType, msgLocErrType_t errType); + + void I_strncpyz_s(char* dest, std::size_t destsize, const char* src, std::size_t count); + void I_strcpy(char* dest, std::size_t destsize, const char* src); } diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp new file mode 100644 index 00000000..876da5fa --- /dev/null +++ b/src/Game/Game.cpp @@ -0,0 +1,23 @@ +#include + +namespace Game +{ + G_LogPrintf_t G_LogPrintf = G_LogPrintf_t(0x4B0150); + G_GetWeaponIndexForName_t G_GetWeaponIndexForName = G_GetWeaponIndexForName_t(0x49E540); + G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = G_SpawnEntitiesFromString_t(0x4D8840); + G_Spawn_t G_Spawn = G_Spawn_t(0x4226F0); + G_FreeEntity_t G_FreeEntity = G_FreeEntity_t(0x44C9D0); + G_SpawnItem_t G_SpawnItem = G_SpawnItem_t(0x403770); + G_GetItemClassname_t G_GetItemClassname = G_GetItemClassname_t(0x492630); + G_PrintEntities_t G_PrintEntities = G_PrintEntities_t(0x4E6A50); + G_GetEntityTypeName_t G_GetEntityTypeName = G_GetEntityTypeName_t(0x4EB810); + + gentity_t* g_entities = reinterpret_cast(0x18835D8); + + XModel* G_GetModel(const int index) + { + assert(index > 0); + assert(index < MAX_MODELS); + return cached_models[index]; + } +} diff --git a/src/Game/Game.hpp b/src/Game/Game.hpp new file mode 100644 index 00000000..9a3a9c9f --- /dev/null +++ b/src/Game/Game.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "BothGames.hpp" +#include "Client.hpp" +#include "Database.hpp" +#include "FileSystem.hpp" +#include "Functions.hpp" +#include "Dvars.hpp" +#include "Script.hpp" +#include "Server.hpp" +#include "System.hpp" + +namespace Game +{ + typedef void(*G_LogPrintf_t)(const char* fmt, ...); + extern G_LogPrintf_t G_LogPrintf; + + typedef unsigned int(*G_GetWeaponIndexForName_t)(const char*); + extern G_GetWeaponIndexForName_t G_GetWeaponIndexForName; + + typedef void(*G_SpawnEntitiesFromString_t)(); + extern G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString; + + typedef gentity_s* (*G_Spawn_t)(); + extern G_Spawn_t G_Spawn; + + typedef void(*G_FreeEntity_t)(gentity_s* ed); + extern G_FreeEntity_t G_FreeEntity; + + typedef void(*G_SpawnItem_t)(gentity_s* ent, int item); + extern G_SpawnItem_t G_SpawnItem; + + typedef void(*G_GetItemClassname_t)(int item, gentity_s* ent); + extern G_GetItemClassname_t G_GetItemClassname; + + typedef void(*G_PrintEntities_t)(); + extern G_PrintEntities_t G_PrintEntities; + + typedef const char*(*G_GetEntityTypeName_t)(const gentity_s* ent); + extern G_GetEntityTypeName_t G_GetEntityTypeName; + + constexpr std::size_t MAX_GENTITIES = 2048; + constexpr std::size_t ENTITYNUM_NONE = MAX_GENTITIES - 1; + extern gentity_t* g_entities; + + extern XModel* G_GetModel(int index); +} diff --git a/src/Game/Script.cpp b/src/Game/Script.cpp new file mode 100644 index 00000000..b7bb7457 --- /dev/null +++ b/src/Game/Script.cpp @@ -0,0 +1,125 @@ +#include + +namespace Game +{ + AddRefToObject_t AddRefToObject = AddRefToObject_t(0x61C360); + RemoveRefToObject_t RemoveRefToObject = RemoveRefToObject_t(0x437190); + AllocObject_t AllocObject = AllocObject_t(0x434320); + AddRefToValue_t AddRefToValue = AddRefToValue_t(0x482740); + AllocThread_t AllocThread = AllocThread_t(0x4F78C0); + + VM_Execute_0_t VM_Execute_0 = VM_Execute_0_t(0x6222A0); + + Scr_GetGameTypeNameForScript_t Scr_GetGameTypeNameForScript = Scr_GetGameTypeNameForScript_t(0x462460); + Scr_IsValidGameType_t Scr_IsValidGameType = Scr_IsValidGameType_t(0x4F1B60); + Scr_LoadGameType_t Scr_LoadGameType = Scr_LoadGameType_t(0x4D9520); + Scr_StartupGameType_t Scr_StartupGameType = Scr_StartupGameType_t(0x438720); + + Scr_LoadScript_t Scr_LoadScript = Scr_LoadScript_t(0x45D940); + Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0); + + Scr_GetString_t Scr_GetString = Scr_GetString_t(0x425900); + Scr_GetConstString_t Scr_GetConstString = Scr_GetConstString_t(0x494830); + Scr_GetDebugString_t Scr_GetDebugString = Scr_GetDebugString_t(0x4EBF50); + Scr_GetFloat_t Scr_GetFloat = Scr_GetFloat_t(0x443140); + Scr_GetInt_t Scr_GetInt = Scr_GetInt_t(0x4F31D0); + Scr_GetObject_t Scr_GetObject = Scr_GetObject_t(0x462100); + Scr_GetTypeName_t Scr_GetTypeName = Scr_GetTypeName_t(0x4EFF10); + Scr_GetNumParam_t Scr_GetNumParam = Scr_GetNumParam_t(0x4B0E90); + Scr_GetEntityId_t Scr_GetEntityId = Scr_GetEntityId_t(0x4165E0); + + Scr_ExecThread_t Scr_ExecThread = Scr_ExecThread_t(0x4AD0B0); + Scr_FreeThread_t Scr_FreeThread = Scr_FreeThread_t(0x4BD320); + + Scr_AddEntity_t Scr_AddEntity = Scr_AddEntity_t(0x4BFB40); + Scr_AddString_t Scr_AddString = Scr_AddString_t(0x412310); + Scr_AddConstString_t Scr_AddConstString = Scr_AddConstString_t(0x488860); + Scr_AddIString_t Scr_AddIString = Scr_AddIString_t(0x455F20); + Scr_AddInt_t Scr_AddInt = Scr_AddInt_t(0x41D7D0); + Scr_AddFloat_t Scr_AddFloat = Scr_AddFloat_t(0x61E860); + Scr_AddObject_t Scr_AddObject = Scr_AddObject_t(0x430F40); + Scr_Notify_t Scr_Notify = Scr_Notify_t(0x4A4750); + Scr_NotifyLevel_t Scr_NotifyLevel = Scr_NotifyLevel_t(0x4D9C30); + + Scr_Error_t Scr_Error = Scr_Error_t(0x61E8B0); + Scr_ObjectError_t Scr_ObjectError = Scr_ObjectError_t(0x42EF40); + Scr_ParamError_t Scr_ParamError = Scr_ParamError_t(0x4FBC70); + + Scr_GetType_t Scr_GetType = Scr_GetType_t(0x422900); + Scr_GetPointerType_t Scr_GetPointerType = Scr_GetPointerType_t(0x4828E0); + + Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0); + + Scr_GetObjectField_t Scr_GetObjectField = Scr_GetObjectField_t(0x4FF3D0); + Scr_SetObjectField_t Scr_SetObjectField = Scr_SetObjectField_t(0x4F20F0); + Scr_GetEntityField_t Scr_GetEntityField = Scr_GetEntityField_t(0x4E8390); + Scr_SetClientField_t Scr_SetClientField = Scr_SetClientField_t(0x4A6DF0); + Scr_AddClassField_t Scr_AddClassField = Scr_AddClassField_t(0x4C0E70); + + GetEntity_t GetEntity = GetEntity_t(0x4BC270); + GetPlayerEntity_t GetPlayerEntity = GetPlayerEntity_t(0x49C4A0); + + Scr_RegisterFunction_t Scr_RegisterFunction = Scr_RegisterFunction_t(0x492D50); + Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode = Scr_ShutdownAllocNode_t(0x441650); + Scr_IsSystemActive_t Scr_IsSystemActive = Scr_IsSystemActive_t(0x4B24E0); + + scr_const_t* scr_const = reinterpret_cast(0x1AA2E00); + + scrVmPub_t* scrVmPub = reinterpret_cast(0x2040CF0); + scrVarPub_t* scrVarPub = reinterpret_cast(0x201A408); + + void IncInParam() + { + Scr_ClearOutParams(); + + if (scrVmPub->top == scrVmPub->maxStack) + { + Sys_Error("Internal script stack overflow"); + } + + scrVmPub->top++; + scrVmPub->inparamcount++; + } + + void Scr_AddBool(int value) + { + assert(value == 0 || value == 1); + + IncInParam(); + scrVmPub->top->type = VAR_INTEGER; + scrVmPub->top->u.intValue = value; + } + + void RuntimeErrorInternal(int channel, const char* codePos, unsigned int index, const char* msg) + { + static DWORD RuntimeErrorInternal_t = 0x61ABE0; + + __asm + { + pushad + mov eax, msg + mov edi, channel + push index + push codePos + call RuntimeErrorInternal_t + add esp, 0x8 + popad + } + } + + void Scr_NotifyId(unsigned int id, unsigned __int16 stringValue, unsigned int paramcount) + { + static DWORD Scr_NotifyId_t = 0x61E670; + + __asm + { + pushad + mov eax, paramcount + push stringValue + push id + call Scr_NotifyId_t + add esp, 8h + popad + } + } +} diff --git a/src/Game/Script.hpp b/src/Game/Script.hpp new file mode 100644 index 00000000..145dccf6 --- /dev/null +++ b/src/Game/Script.hpp @@ -0,0 +1,164 @@ +#pragma once + +namespace Game +{ + typedef void(*AddRefToObject_t)(unsigned int id); + extern AddRefToObject_t AddRefToObject; + + typedef void(*RemoveRefToObject_t)(unsigned int id); + extern RemoveRefToObject_t RemoveRefToObject; + + typedef unsigned int(*AllocObject_t)(); + extern AllocObject_t AllocObject; + + typedef void(*AddRefToValue_t)(int type, VariableUnion u); + extern AddRefToValue_t AddRefToValue; + + typedef unsigned int(*AllocThread_t)(unsigned int self); + extern AllocThread_t AllocThread; + + typedef unsigned int(*VM_Execute_0_t)(unsigned int localId, const char* pos, unsigned int paramcount); + extern VM_Execute_0_t VM_Execute_0; + + typedef void(*Scr_AddEntity_t)(const gentity_s* ent); + extern Scr_AddEntity_t Scr_AddEntity; + + typedef void(*Scr_AddString_t)(const char* value); + extern Scr_AddString_t Scr_AddString; + + typedef void(*Scr_AddConstString_t)(unsigned int value); + extern Scr_AddConstString_t Scr_AddConstString; + + typedef void(*Scr_AddIString_t)(const char* value); + extern Scr_AddIString_t Scr_AddIString; + + typedef void(*Scr_AddInt_t)(int value); + extern Scr_AddInt_t Scr_AddInt; + + typedef void(*Scr_AddFloat_t)(float value); + extern Scr_AddFloat_t Scr_AddFloat; + + typedef void(*Scr_AddObject_t)(unsigned int id); + extern Scr_AddObject_t Scr_AddObject; + + typedef void(*Scr_ShutdownAllocNode_t)(); + extern Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode; + + typedef char* (*Scr_GetGameTypeNameForScript_t)(const char* pszGameTypeScript); + extern Scr_GetGameTypeNameForScript_t Scr_GetGameTypeNameForScript; + + typedef int(*Scr_IsValidGameType_t)(const char* pszGameType); + extern Scr_IsValidGameType_t Scr_IsValidGameType; + + typedef void(*Scr_LoadGameType_t)(); + extern Scr_LoadGameType_t Scr_LoadGameType; + + typedef void(*Scr_StartupGameType_t)(); + extern Scr_StartupGameType_t Scr_StartupGameType; + + typedef int(*Scr_LoadScript_t)(const char*); + extern Scr_LoadScript_t Scr_LoadScript; + + typedef const char*(*Scr_GetString_t)(unsigned int index); + extern Scr_GetString_t Scr_GetString; + + typedef scr_string_t(*Scr_GetConstString_t)(unsigned int index); + extern Scr_GetConstString_t Scr_GetConstString; + + typedef const char* (*Scr_GetDebugString_t)(unsigned int index); + extern Scr_GetDebugString_t Scr_GetDebugString; + + typedef float(*Scr_GetFloat_t)(unsigned int index); + extern Scr_GetFloat_t Scr_GetFloat; + + typedef int(*Scr_GetInt_t)(unsigned int index); + extern Scr_GetInt_t Scr_GetInt; + + typedef unsigned int(*Scr_GetObject_t)(unsigned int index); + extern Scr_GetObject_t Scr_GetObject; + + typedef const char* (*Scr_GetTypeName_t)(unsigned int index); + extern Scr_GetTypeName_t Scr_GetTypeName; + + typedef unsigned int(*Scr_GetNumParam_t)(); + extern Scr_GetNumParam_t Scr_GetNumParam; + + typedef unsigned int(*Scr_GetEntityId_t)(int entnum, unsigned int classnum); + extern Scr_GetEntityId_t Scr_GetEntityId; + + typedef int(*Scr_GetFunctionHandle_t)(const char* filename, const char* name); + extern Scr_GetFunctionHandle_t Scr_GetFunctionHandle; + + typedef int(*Scr_ExecThread_t)(int handle, unsigned int paramcount); + extern Scr_ExecThread_t Scr_ExecThread; + + typedef int(*Scr_ExecEntThread_t)(gentity_s* ent, int handle, unsigned int paramcount); + extern Scr_ExecEntThread_t Scr_ExecEntThread; + + typedef void(*Scr_FreeThread_t)(unsigned __int16 handle); + extern Scr_FreeThread_t Scr_FreeThread; + + typedef void(*Scr_Notify_t)(gentity_t* ent, unsigned __int16 stringValue, unsigned int paramcount); + extern Scr_Notify_t Scr_Notify; + + typedef void(*Scr_NotifyLevel_t)(unsigned __int16 stringValue, unsigned int paramcount); + extern Scr_NotifyLevel_t Scr_NotifyLevel; + + typedef void(*Scr_ClearOutParams_t)(); + extern Scr_ClearOutParams_t Scr_ClearOutParams; + + typedef void(*Scr_RegisterFunction_t)(int func, const char* name); + extern Scr_RegisterFunction_t Scr_RegisterFunction; + + typedef bool(*Scr_IsSystemActive_t)(); + extern Scr_IsSystemActive_t Scr_IsSystemActive; + + typedef int(*Scr_GetType_t)(unsigned int index); + extern Scr_GetType_t Scr_GetType; + + typedef int(*Scr_GetPointerType_t)(unsigned int index); + extern Scr_GetPointerType_t Scr_GetPointerType; + + typedef void(*Scr_Error_t)(const char*); + extern Scr_Error_t Scr_Error; + + typedef void(*Scr_ObjectError_t)(const char*); + extern Scr_ObjectError_t Scr_ObjectError; + + typedef void(*Scr_ParamError_t)(unsigned int paramIndex, const char*); + extern Scr_ParamError_t Scr_ParamError; + + typedef void(*Scr_GetObjectField_t)(unsigned int classnum, int entnum, int offset); + extern Scr_GetObjectField_t Scr_GetObjectField; + + typedef int(*Scr_SetObjectField_t)(unsigned int classnum, int entnum, int offset); + extern Scr_SetObjectField_t Scr_SetObjectField; + + typedef void(*Scr_SetClientField_t)(gclient_s* client, int offset); + extern Scr_SetClientField_t Scr_SetClientField; + + typedef void(*Scr_GetEntityField_t)(int entnum, int offset); + extern Scr_GetEntityField_t Scr_GetEntityField; + + typedef void(*Scr_AddClassField_t)(unsigned int classnum, const char* name, unsigned int offset); + extern Scr_AddClassField_t Scr_AddClassField; + + typedef gentity_s*(*GetPlayerEntity_t)(scr_entref_t entref); + extern GetPlayerEntity_t GetPlayerEntity; + + typedef gentity_s*(*GetEntity_t)(scr_entref_t entref); + extern GetEntity_t GetEntity; + + extern void IncInParam(); + + extern void Scr_AddBool(int value); + + extern void RuntimeErrorInternal(int channel, const char* codePos, unsigned int index, const char* msg); + + extern void Scr_NotifyId(unsigned int id, unsigned __int16 stringValue, unsigned int paramcount); + + extern scr_const_t* scr_const; + + extern scrVmPub_t* scrVmPub; + extern scrVarPub_t* scrVarPub; +} diff --git a/src/Game/Server.cpp b/src/Game/Server.cpp new file mode 100644 index 00000000..f5a5654b --- /dev/null +++ b/src/Game/Server.cpp @@ -0,0 +1,67 @@ +#include + +namespace Game +{ + SV_AddTestClient_t SV_AddTestClient = SV_AddTestClient_t(0x48AD30); + SV_IsTestClient_t SV_IsTestClient = SV_IsTestClient_t(0x4D6E40); + SV_GameClientNum_Score_t SV_GameClientNum_Score = SV_GameClientNum_Score_t(0x469AC0); + SV_GameSendServerCommand_t SV_GameSendServerCommand = SV_GameSendServerCommand_t(0x4BC3A0); + SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString = SV_Cmd_TokenizeString_t(0x4B5780); + SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString = SV_Cmd_EndTokenizedString_t(0x464750); + SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer = SV_Cmd_ArgvBuffer_t(0x40BB60); + SV_DirectConnect_t SV_DirectConnect = SV_DirectConnect_t(0x460480); + SV_SetConfigstring_t SV_SetConfigstring = SV_SetConfigstring_t(0x4982E0); + SV_Loaded_t SV_Loaded = SV_Loaded_t(0x4EE3E0); + SV_ClientThink_t SV_ClientThink = SV_ClientThink_t(0x44ADD0); + SV_DropClient_t SV_DropClient = SV_DropClient_t(0x4D1600); + SV_GetPlayerByName_t SV_GetPlayerByName = SV_GetPlayerByName_t(0x6242B0); + SV_GetPlayerByNum_t SV_GetPlayerByNum = SV_GetPlayerByNum_t(0x624390); + SV_FindClientByAddress_t SV_FindClientByAddress = SV_FindClientByAddress_t(0x44F450); + + int* svs_time = reinterpret_cast(0x31D9384); + int* sv_serverId_value = reinterpret_cast(0x2089DC0); + int* svs_clientCount = reinterpret_cast(0x31D938C); + client_t* svs_clients = reinterpret_cast(0x31D9390); + + volatile long* sv_thread_owns_game = reinterpret_cast(0x2089DB8); + + int SV_GetServerThreadOwnsGame() + { + return *sv_thread_owns_game; + } + + void SV_GameDropClient(int clientNum, const char* reason) + { + assert((*sv_maxclients)->current.integer >= 1 && (*sv_maxclients)->current.integer <= 18); + + if (clientNum >= 0 && clientNum < (*sv_maxclients)->current.integer) + { + SV_DropClient(&svs_clients[clientNum], reason, true); + } + } + + void SV_DropAllBots() + { + for (auto i = 0; i < *svs_clientCount; ++i) + { + if (svs_clients[i].header.state != CS_FREE + && svs_clients[i].header.netchan.remoteAddress.type == NA_BOT) + { + SV_GameDropClient(i, "GAME_GET_TO_COVER"); + } + } + } + + void SV_BotUserMove(client_t* client) + { + static DWORD SV_BotUserMove_t = 0x626E50; + + __asm + { + pushad + mov edi, client + call SV_BotUserMove_t + popad + } + } +} diff --git a/src/Game/Server.hpp b/src/Game/Server.hpp new file mode 100644 index 00000000..c7c61bef --- /dev/null +++ b/src/Game/Server.hpp @@ -0,0 +1,61 @@ +#pragma once + +namespace Game +{ + typedef gentity_t*(*SV_AddTestClient_t)(); + extern SV_AddTestClient_t SV_AddTestClient; + + typedef int(*SV_IsTestClient_t)(int clientNum); + extern SV_IsTestClient_t SV_IsTestClient; + + typedef int(*SV_GameClientNum_Score_t)(int clientID); + extern SV_GameClientNum_Score_t SV_GameClientNum_Score; + + typedef void(*SV_GameSendServerCommand_t)(int clientNum, svscmd_type type, const char* text); + extern SV_GameSendServerCommand_t SV_GameSendServerCommand; + + typedef void(*SV_Cmd_TokenizeString_t)(const char* string); + extern SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString; + + typedef void(*SV_Cmd_EndTokenizedString_t)(); + extern SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString; + + typedef void(*SV_Cmd_ArgvBuffer_t)(int arg, char* buf, int size); + extern SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer; + + typedef void(*SV_SetConfigstring_t)(int index, const char* string); + extern SV_SetConfigstring_t SV_SetConfigstring; + + typedef void(*SV_DirectConnect_t)(netadr_t adr); + extern SV_DirectConnect_t SV_DirectConnect; + + typedef bool(*SV_Loaded_t)(); + extern SV_Loaded_t SV_Loaded; + + typedef void(*SV_ClientThink_t)(client_t* cl, usercmd_s* cmd); + extern SV_ClientThink_t SV_ClientThink; + + typedef void(*SV_DropClient_t)(client_t* drop, const char* reason, bool tellThem); + extern SV_DropClient_t SV_DropClient; + + typedef client_t* (*SV_GetPlayerByName_t)(); + extern SV_GetPlayerByName_t SV_GetPlayerByName; + + typedef client_t* (*SV_GetPlayerByNum_t)(); + extern SV_GetPlayerByNum_t SV_GetPlayerByNum; + + typedef client_t* (*SV_FindClientByAddress_t)(netadr_t from, int qport, int remoteClientIndex); + extern SV_FindClientByAddress_t SV_FindClientByAddress; + + extern int* svs_time; + extern int* sv_serverId_value; + extern int* svs_clientCount; + extern client_t* svs_clients; + + extern volatile long* sv_thread_owns_game; + + extern int SV_GetServerThreadOwnsGame(); + extern void SV_GameDropClient(int clientNum, const char* reason); + extern void SV_DropAllBots(); + extern void SV_BotUserMove(client_t* client); +} diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index af92e04d..309b8173 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -220,7 +220,7 @@ namespace Game DVAR_SOURCE_DEVGUI = 0x3, }; - typedef enum : char + enum dvar_type : char { DVAR_TYPE_BOOL = 0x0, DVAR_TYPE_FLOAT = 0x1, @@ -233,9 +233,9 @@ namespace Game DVAR_TYPE_COLOR = 0x8, DVAR_TYPE_FLOAT_3_COLOR = 0x9, DVAR_TYPE_COUNT = 0xA, - } dvar_type; + }; - typedef enum + enum clientState_t { CS_FREE = 0x0, CS_ZOMBIE = 0x1, @@ -243,7 +243,7 @@ namespace Game CS_CONNECTED = 0x3, CS_CLIENTLOADING = 0x4, CS_ACTIVE = 0x5, - } clientState_t; + }; enum serverState_t { @@ -264,6 +264,17 @@ namespace Game ERR_MAPLOADERRORSUMMARY = 0x7 }; + enum ConfigString + { + CS_VOTE_TIME = 0x11, + CS_VOTE_STRING = 0x12, + CS_VOTE_YES = 0x13, + CS_VOTE_NO = 0x14, + CS_VOTE_MAPNAME = 0x15, + CS_VOTE_GAMETYPE = 0x16, + CS_ITEMS = 0x102A, + }; // Incomplete + enum conChannel_t { CON_CHANNEL_DONT_FILTER, @@ -296,6 +307,27 @@ namespace Game CON_BUILTIN_CHANNEL_COUNT, }; + enum meansOfDeath_t + { + MOD_UNKNOWN = 0x0, + MOD_PISTOL_BULLET = 0x1, + MOD_RIFLE_BULLET = 0x2, + MOD_EXPLOSIVE_BULLET = 0x3, + MOD_GRENADE = 0x4, + MOD_GRENADE_SPLASH = 0x5, + MOD_PROJECTILE = 0x6, + MOD_PROJECTILE_SPLASH = 0x7, + MOD_MELEE = 0x8, + MOD_HEAD_SHOT = 0x9, + MOD_CRUSH = 0xA, + MOD_FALLING = 0xB, + MOD_SUICIDE = 0xC, + MOD_TRIGGER_HURT = 0xD, + MOD_EXPLOSIVE = 0xE, + MOD_IMPACT = 0xF, + MOD_NUM = 0x10, + }; + enum { FL_GODMODE = 1 << 0, @@ -1258,13 +1290,7 @@ namespace Game int flags; }; - struct $3EB5F037EADAEE8E2FA2A1F9FFF31312 - { - hudelem_s current[31]; - hudelem_s archival[31]; - }; - - enum playerStateFlag + enum { PMF_PRONE = 1 << 0, PMF_DUCKED = 1 << 1, @@ -1291,7 +1317,7 @@ namespace Game PMF_DIVING = 1 << 22, }; - enum playerStateOtherFlag + enum { POF_INVULNERABLE = 1 << 0, POF_REMOTE_EYES = 1 << 1, @@ -1327,7 +1353,7 @@ namespace Game PM_DEAD_LINKED = 0x9, }; - enum playerEFlag + enum { EF_NONSOLID_BMODEL = 1 << 0, EF_TELEPORT_BIT = 1 << 1, @@ -1355,14 +1381,14 @@ namespace Game EF_SOFT = 1 << 23, }; - enum playerLinkFlag + enum { PLF_ANGLES_LOCKED = 1 << 0, PLF_USES_OFFSET = 1 << 1, PLF_WEAPONVIEW_ONLY = 1 << 2, }; - enum playerWeaponFlag + enum { PWF_USE_RELOAD = 1 << 0, PWF_USING_OFFHAND = 1 << 1, @@ -1497,14 +1523,18 @@ namespace Game int killCamEntity; int killCamLookAtEntity; int killCamClientNum; - $3EB5F037EADAEE8E2FA2A1F9FFF31312 hud; + struct + { + hudelem_s current[31]; + hudelem_s archival[31]; + } hud; unsigned int partBits[6]; int recoilScale; int diveDirection; int stunTime; }; - static_assert(sizeof(Game::playerState_s) == 0x311C); + static_assert(sizeof(playerState_s) == 0x311C); enum LocSelInputState { @@ -3591,19 +3621,21 @@ namespace Game unsigned char color[4]; }; - struct $BFBB53559BEAC4289F32B924847E59CB + static_assert(sizeof(DvarValue) == 0x10); + + struct enum_limit { int stringCount; const char** strings; }; - struct $9CA192F9DB66A3CB7E01DE78A0DEA53D + struct int_limit { int min; int max; }; - struct $251C2428A496074035CACA7AAF3D55BD + struct float_limit { float min; float max; @@ -3611,12 +3643,14 @@ namespace Game union DvarLimits { - $BFBB53559BEAC4289F32B924847E59CB enumeration; - $9CA192F9DB66A3CB7E01DE78A0DEA53D integer; - $251C2428A496074035CACA7AAF3D55BD value; - $251C2428A496074035CACA7AAF3D55BD vector; + enum_limit enumeration; + int_limit integer; + float_limit value; + float_limit vector; }; + static_assert(sizeof(DvarLimits) == 0x8); + struct dvar_t { const char* name; @@ -3629,9 +3663,11 @@ namespace Game DvarValue reset; DvarLimits domain; bool(__cdecl * domainFunc)(dvar_t*, DvarValue); - dvar_t *hashNext; + dvar_t* hashNext; }; + static_assert(sizeof(dvar_t) == 0x50); + struct StaticDvar { dvar_t* dvar; @@ -5234,7 +5270,7 @@ namespace Game int stringOffsets[4139]; char stringData[131072]; int dataCount; - } gameState; + }; struct HunkUser { @@ -5657,18 +5693,16 @@ namespace Game UILOCALVAR_STRING = 0x2, }; - union $B42A88463653BDCDFC5664844B4491DA - { - int integer; - float value; - const char *string; - }; - struct UILocalVar { UILocalVarType type; - const char *name; - $B42A88463653BDCDFC5664844B4491DA u; + const char* name; + union + { + int integer; + float value; + const char* string; + } u; }; struct UILocalVarContext @@ -5676,20 +5710,18 @@ namespace Game UILocalVar table[256]; }; - struct $1942E78D15753E2013144570239460A8 - { - float x; - float y; - int lastMoveTime; - }; - struct UiContext { int localClientNum; float bias; int realTime; int frameTime; - $1942E78D15753E2013144570239460A8 cursor; + struct + { + float x; + float y; + int lastMoveTime; + } cursor; int isCursorVisible; int paintFull; int screenWidth; @@ -5697,9 +5729,9 @@ namespace Game float screenAspect; float FPS; float blurRadiusOut; - menuDef_t *Menus[640]; + menuDef_t* Menus[640]; int menuCount; - menuDef_t *menuStack[16]; + menuDef_t* menuStack[16]; int openMenuCount; UILocalVarContext localVars; }; @@ -5708,8 +5740,8 @@ namespace Game { int overflowed; int readOnly; - char *data; - char *splitData; + unsigned char *data; + unsigned char *splitData; int maxsize; int cursize; int splitSize; @@ -6301,19 +6333,50 @@ namespace Game bool topFire; }; -#pragma pack(push, 1) - - typedef struct client_s + struct clientHeader_t { - clientState_t state; // 0 - int sendAsActive; // 4 - int deltaMessage; // 8 - char __pad1[12]; // 12 - netchan_t netchan; // 24 - char __pad2[20]; // 1604 - const char* delayDropReason; // 1624 + int state; + int sendAsActive; + int deltaMessage; + int rateDelayed; + int hasAckedBaselineData; + int hugeSnapshotSent; + netchan_t netchan; + float predictedOrigin[3]; + int predictedOriginServerTime; + int migrationState; + }; + + static_assert(sizeof(clientHeader_t) == 1624); + + struct svscmd_info_t + { + char cmd[1024]; + int time; + int type; + }; + + struct clientSnapshot_t + { + playerState_s ps; + int num_entities; + int num_clients; + int first_entity; + int first_client; + int messageSent; + int messageAcked; + int messageSize; + int serverTime; + int timeDelta; + int baselineSnap; + }; + + struct client_t + { + clientHeader_t header; + const char* dropReason; // 1624 char userinfo[1024]; // 1628 - char __pad3[132096]; // 2652 + svscmd_info_t reliableCommandInfo[128]; // 2652 int reliableSequence; // 134748 int reliableAcknowledge; // 134752 int reliableSent; // 134756 @@ -6328,21 +6391,31 @@ namespace Game int nextReliableTime; // 135860 int lastPacketTime; // 135864 int lastConnectTime; // 135868 - int snapNum; // 135872 - int __pad5; // 135876 - short ping; // 135880 - char __pad6[14]; // 135882 + int nextSnapshotTime; // 135872 + int timeoutCount; // 135876 + int ping; // 135880 + int rate; + int snapshotMsec; + int snapshotBackoffCount; int pureAuthentic; // 135896 - char __pad7[133138]; // 135900 - short scriptID; // 269038 + char netchanOutgoingBuffer[131072]; + char netchanIncomingBuffer[2048]; + char playerGuid[17]; + unsigned short scriptId; // 269038 int bIsTestClient; // 269040 int serverID; // 269044 - char __pad8[9224]; // 269048 + bool usingOnlineStatsOffline; + char stats[8192]; + char statsModifiedFlags[1024]; + bool statsModified; + char statPacketsReceived; + bool steamAuthorized; + char steamAuthFailCount; unsigned __int64 steamID; // 278272 - char __pad9[403592]; // 278280 - } client_t; - -#pragma pack(pop) + bool sendMatchData; + int matchDataSendTime; + clientSnapshot_t frames[32]; + }; static_assert(sizeof(client_t) == 0xA6790); @@ -7574,7 +7647,7 @@ namespace Game static_assert(sizeof(cg_s) == 0xFD540); - static constexpr auto MAX_GAMEPADS = 1; + static constexpr auto MAX_GPAD_COUNT = 1; static constexpr auto GPAD_VALUE_MASK = 0xFFFFFFFu; static constexpr auto GPAD_DPAD_MASK = XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT; @@ -8761,32 +8834,139 @@ namespace Game bool isRunning; bool cgameInitialized; bool cgameInitCalled; - bool mapPreloaded; - clientMigState_t migrationState; - MigrationPers migrationPers; - MigrationVerboseState verboseMigrationState; - int verboseMigrationData; + unsigned char __pad0[0x9AC]; int keyCatchers; bool displayHUDWithKeycatchUI; connstate_t connectionState; - bool invited; - char itemsUnlocked[256]; - bool itemsUnlockedInited; - bool itemsUnlockedLastGameDirty; - unsigned __int16 itemsUnlockedLastGame[16]; - int itemsUnlockedLastGameCount; - char* itemsUnlockedBuffer; - int itemsUnlockedLocalClientNum; - int itemsUnlockedControllerIndex; - int itemsUnlockedStatsSource; + unsigned char __pad1[0x138]; }; + static_assert(sizeof(clientUIActive_t) == 0xAF4); + enum msgLocErrType_t { LOCMSG_SAFE = 0x0, LOCMSG_NOERR = 0x1, }; + struct ImageList + { + unsigned int count; + GfxImage* image[8192]; + }; + + enum CriticalSection + { + CRITSECT_CONSOLE, + CRITSECT_DEBUG_SOCKET, + CRITSECT_COM_ERROR, + CRITSECT_STATMON, + CRITSECT_ALLOC_MARK, + CRITSECT_GENERATE_MARK, + CRITSECT_STREAMED_SOUND, + CRITSECT_FAKELAG, + CRITSECT_CLIENT_MESSAGE, + CRITSECT_CLIENT_CMD, + CRITSECT_DOBJ_ALLOC, + CRITSECT_START_SERVER, + CRITSECT_XANIM_ALLOC, + CRITSECT_KEY_BINDINGS, + CRITSECT_FX_VIS, + CRITSECT_SERVER_MESSAGE, + CRITSECT_SCRIPT_STRING, + CRITSECT_RD_BUFFER, + CRITSECT_SYS_EVENT_QUEUE, + CRITSECT_GPU_FENCE, + CRITSECT_FATAL_ERROR, + CRITSECT_MISSING_ASSET, + CRITSECT_PHYSICS, + CRITSECT_LIVE, + CRITSECT_AUDIO_PHYSICS, + CRITSECT_LSP, + CRITSECT_CINEMATIC_UPDATE, + CRITSECT_CINEMATIC_TARGET_CHANGE_COMMAND, + CRITSECT_CINEMATIC_TARGET_CHANGE_BACKEND, + CRITSECT_CINEMATIC_STATUS, + CRITSECT_CINEMATIC_SERVER, + CRITSECT_FX_ALLOC, + CRITSECT_NETTHREAD_OVERRIDE, + CRITSECT_CBUF, + CRITSECT_STATS_WRITE, + CRITSECT_CG_GLASS, + CRITSECT_SERVER_DEMO_COMPRESS, + CRITSECT_COM_SET_ERROR_MSG, + CRITSECT_SOUND_UPDATE, + CRITSECT_RESET_MODEL_LIGHTING, + + CRITSECT_COUNT, + }; // May be incorrect + + struct ClientVoicePacket_t + { + char data[256]; + int dataSize; + }; + + struct voiceCommunication_t + { + ClientVoicePacket_t voicePackets[10]; + int voicePacketCount; + int voicePacketLastTransmit; + int packetsPerSec; + int packetsPerSecStart; + }; + + struct VoicePacket_t + { + char talker; + char data[256]; + int dataSize; + }; + + struct uiInfo_s + { + UiContext uiDC; + int myTeamCount; + int playerRefresh; + int playerIndex; + int timeIndex; + int previousTimes[4]; + uiMenuCommand_t currentMenuType; + bool allowScriptMenuResponse; + char findPlayerName[1024]; + char foundPlayerServerAddresses[16][64]; + char foundPlayerServerNames[16][64]; + int numFoundPlayerServers; + int nextFindPlayerRefresh; + unsigned int mailUpdateTime; + char mailIndices[64]; + int mailCount; + int selectedMail; + }; + + enum entityType_t + { + ET_GENERAL = 0x0, + ET_PLAYER = 0x1, + ET_PLAYER_CORPSE = 0x2, + ET_ITEM = 0x3, + ET_MISSILE = 0x4, + ET_INVISIBLE = 0x5, + ET_SCRIPTMOVER = 0x6, + ET_SOUND_BLEND = 0x7, + ET_FX = 0x8, + ET_LOOP_FX = 0x9, + ET_PRIMARY_LIGHT = 0xA, + ET_TURRET = 0xB, + ET_HELICOPTER = 0xC, + ET_PLANE = 0xD, + ET_VEHICLE = 0xE, + ET_VEHICLE_COLLMAP = 0xF, + ET_VEHICLE_CORPSE = 0x10, + ET_VEHICLE_SPAWNER = 0x11, + ET_EVENTS = 0x12, + }; + #pragma endregion #ifndef IDA diff --git a/src/Game/System.cpp b/src/Game/System.cpp new file mode 100644 index 00000000..9a85028b --- /dev/null +++ b/src/Game/System.cpp @@ -0,0 +1,38 @@ +#include + +namespace Game +{ + Sys_FreeFileList_t Sys_FreeFileList = Sys_FreeFileList_t(0x4D8580); + Sys_IsDatabaseReady_t Sys_IsDatabaseReady = Sys_IsDatabaseReady_t(0x4CA4A0); + Sys_IsDatabaseReady2_t Sys_IsDatabaseReady2 = Sys_IsDatabaseReady2_t(0x441280); + Sys_IsMainThread_t Sys_IsMainThread = Sys_IsMainThread_t(0x4C37D0); + Sys_IsRenderThread_t Sys_IsRenderThread = Sys_IsRenderThread_t(0x4B20E0); + Sys_IsServerThread_t Sys_IsServerThread = Sys_IsServerThread_t(0x4B0270); + Sys_IsDatabaseThread_t Sys_IsDatabaseThread = Sys_IsDatabaseThread_t(0x4C6020); + Sys_ListFiles_t Sys_ListFiles = Sys_ListFiles_t(0x45A660); + Sys_Milliseconds_t Sys_Milliseconds = Sys_Milliseconds_t(0x42A660); + Sys_Error_t Sys_Error = Sys_Error_t(0x43D570); + Sys_LockWrite_t Sys_LockWrite = Sys_LockWrite_t(0x435880); + Sys_TempPriorityAtLeastNormalBegin_t Sys_TempPriorityAtLeastNormalBegin = Sys_TempPriorityAtLeastNormalBegin_t(0x478680); + Sys_TempPriorityEnd_t Sys_TempPriorityEnd = Sys_TempPriorityEnd_t(0x4DCF00); + Sys_EnterCriticalSection_t Sys_EnterCriticalSection = Sys_EnterCriticalSection_t(0x4FC200); + Sys_LeaveCriticalSection_t Sys_LeaveCriticalSection = Sys_LeaveCriticalSection_t(0x41B8C0); + Sys_DefaultInstallPath_t Sys_DefaultInstallPath = Sys_DefaultInstallPath_t(0x4326E0); + Sys_SendPacket_t Sys_SendPacket = Sys_SendPacket_t(0x60FDC0); + Sys_ShowConsole_t Sys_ShowConsole = Sys_ShowConsole_t(0x4305E0); + Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads = Sys_SuspendOtherThreads_t(0x45A190); + + char(*sys_exitCmdLine)[1024] = reinterpret_cast(0x649FB68); + + void Sys_LockRead(FastCriticalSection* critSect) + { + InterlockedIncrement(&critSect->readCount); + while (critSect->writeCount) std::this_thread::sleep_for(1ms); + } + + void Sys_UnlockRead(FastCriticalSection* critSect) + { + assert(critSect->readCount > 0); + InterlockedDecrement(&critSect->readCount); + } +} diff --git a/src/Game/System.hpp b/src/Game/System.hpp new file mode 100644 index 00000000..5265f736 --- /dev/null +++ b/src/Game/System.hpp @@ -0,0 +1,67 @@ +#pragma once + +namespace Game +{ + + typedef void(*Sys_Error_t)(const char* error, ...); + extern Sys_Error_t Sys_Error; + + typedef void(*Sys_FreeFileList_t)(const char** list); + extern Sys_FreeFileList_t Sys_FreeFileList; + + typedef int(*Sys_IsDatabaseReady_t)(); + extern Sys_IsDatabaseReady_t Sys_IsDatabaseReady; + + typedef int(*Sys_IsDatabaseReady2_t)(); + extern Sys_IsDatabaseReady2_t Sys_IsDatabaseReady2; + + typedef bool(*Sys_IsMainThread_t)(); + extern Sys_IsMainThread_t Sys_IsMainThread; + + typedef bool(*Sys_IsRenderThread_t)(); + extern Sys_IsRenderThread_t Sys_IsRenderThread; + + typedef bool(*Sys_IsServerThread_t)(); + extern Sys_IsServerThread_t Sys_IsServerThread; + + typedef bool(*Sys_IsDatabaseThread_t)(); + extern Sys_IsDatabaseThread_t Sys_IsDatabaseThread; + + typedef const char**(*Sys_ListFiles_t)(const char* directory, const char* extension, const char* filter, int* numfiles, int wantsubs); + extern Sys_ListFiles_t Sys_ListFiles; + + typedef int(*Sys_Milliseconds_t)(); + extern Sys_Milliseconds_t Sys_Milliseconds; + + typedef void(*Sys_LockWrite_t)(FastCriticalSection* critSect); + extern Sys_LockWrite_t Sys_LockWrite; + + typedef void(*Sys_TempPriorityAtLeastNormalBegin_t)(TempPriority*); + extern Sys_TempPriorityAtLeastNormalBegin_t Sys_TempPriorityAtLeastNormalBegin; + + typedef void(*Sys_TempPriorityEnd_t)(TempPriority*); + extern Sys_TempPriorityEnd_t Sys_TempPriorityEnd; + + typedef void(*Sys_EnterCriticalSection_t)(CriticalSection critSect); + extern Sys_EnterCriticalSection_t Sys_EnterCriticalSection; + + typedef void(*Sys_LeaveCriticalSection_t)(CriticalSection critSect); + extern Sys_LeaveCriticalSection_t Sys_LeaveCriticalSection; + + typedef char*(*Sys_DefaultInstallPath_t)(); + extern Sys_DefaultInstallPath_t Sys_DefaultInstallPath; + + typedef bool(*Sys_SendPacket_t)(netsrc_t sock, size_t len, const char* format, netadr_t adr); + extern Sys_SendPacket_t Sys_SendPacket; + + typedef void(*Sys_ShowConsole_t)(); + extern Sys_ShowConsole_t Sys_ShowConsole; + + typedef void(*Sys_SuspendOtherThreads_t)(); + extern Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads; + + extern char(*sys_exitCmdLine)[1024]; + + extern void Sys_LockRead(FastCriticalSection* critSect); + extern void Sys_UnlockRead(FastCriticalSection* critSect); +} diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 4ea171d8..8fb0fca8 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -5,8 +5,6 @@ #ifndef RC_INVOKED -//#define _HAS_CXX17 1 -//#define _HAS_CXX20 1 #define VC_EXTRALEAN #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_WARNINGS @@ -17,6 +15,8 @@ //#include #include +#include +#include #include #include #include @@ -78,9 +78,7 @@ #include #include -#include #include -#include #include #include @@ -95,6 +93,12 @@ using namespace std::literals; #undef min #endif +// Needs to be included after the nominmax above ^ +#ifdef snprintf + #undef snprintf +#endif +#include + #define AssertSize(x, size) \ static_assert(sizeof(x) == (size), \ "Structure has an invalid size. " #x " must be " #size " bytes") @@ -103,6 +107,10 @@ using namespace std::literals; static_assert(offsetof(x, y) == (offset), \ #x "::" #y " is not at the right offset. Must be at " #offset) +#define AssertIn(x, y) assert(static_cast(x) < static_cast(y)) + +#define AssertUnreachable assert(0 && "unreachable") + // Protobuf #include "proto/session.pb.h" #include "proto/party.pb.h" @@ -139,7 +147,8 @@ using namespace std::literals; #include "Steam/Steam.hpp" // Some definitions are used in functions and structs #include "Game/Structs.hpp" -#include "Game/Functions.hpp" +#include "Game/Game.hpp" + #include #include diff --git a/src/Steam/Interfaces/SteamFriends.cpp b/src/Steam/Interfaces/SteamFriends.cpp index 6b5fbe27..49ff9d79 100644 --- a/src/Steam/Interfaces/SteamFriends.cpp +++ b/src/Steam/Interfaces/SteamFriends.cpp @@ -6,7 +6,7 @@ STEAM_IGNORE_WARNINGS_START namespace Steam { - const char *Friends::GetPersonaName() + const char* Friends::GetPersonaName() { return Dvar::Var("name").get(); } @@ -28,7 +28,7 @@ namespace Steam SteamID Friends::GetFriendByIndex(int iFriend, int iFriendFlags) { - return SteamID(); + return {}; } int Friends::GetFriendRelationship(SteamID steamIDFriend) @@ -41,7 +41,7 @@ namespace Steam return 0; } - const char *Friends::GetFriendPersonaName(SteamID steamIDFriend) + const char* Friends::GetFriendPersonaName(SteamID steamIDFriend) { return ""; } @@ -56,7 +56,7 @@ namespace Steam return false; } - const char *Friends::GetFriendPersonaNameHistory(SteamID steamIDFriend, int iPersonaName) + const char* Friends::GetFriendPersonaNameHistory(SteamID steamIDFriend, int iPersonaName) { return ""; } @@ -88,7 +88,7 @@ namespace Steam SteamID Friends::GetFriendFromSourceByIndex(SteamID steamIDSource, int iFriend) { - return SteamID(); + return {}; } bool Friends::IsUserInSource(SteamID steamIDUser, SteamID steamIDSource) diff --git a/src/Steam/Interfaces/SteamFriends.hpp b/src/Steam/Interfaces/SteamFriends.hpp index 2b4ab668..f3a06e06 100644 --- a/src/Steam/Interfaces/SteamFriends.hpp +++ b/src/Steam/Interfaces/SteamFriends.hpp @@ -20,21 +20,21 @@ namespace Steam class Friends { public: - virtual const char *GetPersonaName(); + virtual const char* GetPersonaName(); virtual void SetPersonaName(const char *pchPersonaName); virtual int GetPersonaState(); virtual int GetFriendCount(int eFriendFlags); virtual SteamID GetFriendByIndex(int iFriend, int iFriendFlags); virtual int GetFriendRelationship(SteamID steamIDFriend); virtual int GetFriendPersonaState(SteamID steamIDFriend); - virtual const char *GetFriendPersonaName(SteamID steamIDFriend); + virtual const char* GetFriendPersonaName(SteamID steamIDFriend); virtual int GetFriendAvatar(SteamID steamIDFriend, int eAvatarSize); virtual bool GetFriendGamePlayed(SteamID steamIDFriend, FriendGameInfo *pFriendGameInfo); - virtual const char *GetFriendPersonaNameHistory(SteamID steamIDFriend, int iPersonaName); + virtual const char* GetFriendPersonaNameHistory(SteamID steamIDFriend, int iPersonaName); virtual bool HasFriend(SteamID steamIDFriend, int eFriendFlags); virtual int GetClanCount(); virtual SteamID GetClanByIndex(int iClan); - virtual const char *GetClanName(SteamID steamIDClan); + virtual const char* GetClanName(SteamID steamIDClan); virtual int GetFriendCountFromSource(SteamID steamIDSource); virtual SteamID GetFriendFromSourceByIndex(SteamID steamIDSource, int iFriend); virtual bool IsUserInSource(SteamID steamIDUser, SteamID steamIDSource); @@ -49,28 +49,28 @@ namespace Steam class Friends15 { public: - virtual const char *GetPersonaName() = 0; + virtual const char* GetPersonaName() = 0; virtual uint64_t SetPersonaName(const char *pchPersonaName) = 0; virtual int GetPersonaState() = 0; virtual int GetFriendCount(int iFriendFlags) = 0; virtual SteamID GetFriendByIndex(int iFriend, int iFriendFlags) = 0; virtual int GetFriendRelationship(SteamID steamIDFriend) = 0; virtual int GetFriendPersonaState(SteamID steamIDFriend) = 0; - virtual const char *GetFriendPersonaName(SteamID steamIDFriend) = 0; + virtual const char* GetFriendPersonaName(SteamID steamIDFriend) = 0; virtual bool GetFriendGamePlayed(SteamID steamID, void *pGamePlayInfo) = 0; - virtual const char *GetFriendPersonaNameHistory(SteamID steamIDFriend, FriendGameInfo iPersonaName) = 0; + virtual const char* GetFriendPersonaNameHistory(SteamID steamIDFriend, FriendGameInfo iPersonaName) = 0; virtual int GetFriendSteamLevel(SteamID steamIDFriend) = 0; - virtual const char *GetPlayerNickname(SteamID steamIDPlayer) = 0; + virtual const char* GetPlayerNickname(SteamID steamIDPlayer) = 0; virtual int16_t GetFriendsGroupCount() = 0; virtual int16_t GetFriendsGroupIDByIndex(int32_t) = 0; - virtual const char * GetFriendsGroupName(int16_t) = 0; + virtual const char* GetFriendsGroupName(int16_t) = 0; virtual int GetFriendsGroupMembersCount(int16_t) = 0; virtual int GetFriendsGroupMembersList(int16_t, SteamID *, int32_t) = 0; virtual bool HasFriend(SteamID steamIDFriend, int iFriendFlags) = 0; virtual int GetClanCount() = 0; virtual SteamID GetClanByIndex(int iClan) = 0; - virtual const char *GetClanName(SteamID steamIDClan) = 0; - virtual const char *GetClanTag(SteamID steamIDClan) = 0; + virtual const char* GetClanName(SteamID steamIDClan) = 0; + virtual const char* GetClanTag(SteamID steamIDClan) = 0; virtual bool GetClanActivityCounts(SteamID steamID, int *pnOnline, int *pnInGame, int *pnChatting) = 0; virtual uint64_t DownloadClanActivityCounts(SteamID groupIDs[], int nIds) = 0; virtual int GetFriendCountFromSource(SteamID steamIDSource) = 0; @@ -94,9 +94,9 @@ namespace Steam virtual int GetUserRestrictions() = 0; virtual bool SetRichPresence(const char *pchKey, const char *pchValue) = 0; virtual void ClearRichPresence() = 0; - virtual const char *GetFriendRichPresence(SteamID steamIDFriend, const char *pchKey) = 0; + virtual const char* GetFriendRichPresence(SteamID steamIDFriend, const char *pchKey) = 0; virtual int GetFriendRichPresenceKeyCount(SteamID steamIDFriend) = 0; - virtual const char *GetFriendRichPresenceKeyByIndex(SteamID steamIDFriend, int iKey) = 0; + virtual const char* GetFriendRichPresenceKeyByIndex(SteamID steamIDFriend, int iKey) = 0; virtual void RequestFriendRichPresence(SteamID steamIDFriend) = 0; virtual bool InviteUserToGame(SteamID steamIDFriend, const char *pchConnectString) = 0; virtual int GetCoplayFriendCount() = 0; diff --git a/src/Utils/Cache.cpp b/src/Utils/Cache.cpp index f2e7a6f4..17390b83 100644 --- a/src/Utils/Cache.cpp +++ b/src/Utils/Cache.cpp @@ -48,10 +48,4 @@ namespace Utils return Utils::WebIO(useragent, Cache::GetUrl(Cache::ValidUrl, path)).setTimeout(timeout)->get(); } } - - void Cache::Uninitialize() - { - std::lock_guard _(Cache::CacheMutex); - Cache::ValidUrl.clear(); - } } diff --git a/src/Utils/Cache.hpp b/src/Utils/Cache.hpp index d51053b9..73b772fa 100644 --- a/src/Utils/Cache.hpp +++ b/src/Utils/Cache.hpp @@ -7,7 +7,6 @@ namespace Utils public: static std::string GetStaticUrl(const std::string& path); static std::string GetFile(const std::string& path, int timeout = 5000, const std::string& useragent = "IW4x"); - static void Uninitialize(); private: static std::mutex CacheMutex; diff --git a/src/Utils/IO.cpp b/src/Utils/IO.cpp index 78f8d042..d0522fd7 100644 --- a/src/Utils/IO.cpp +++ b/src/Utils/IO.cpp @@ -54,7 +54,7 @@ namespace Utils if (size > -1) { data->resize(static_cast(size)); - stream.read(const_cast(data->data()), size); + stream.read(data->data(), size); stream.close(); return true; } diff --git a/src/Utils/InfoString.cpp b/src/Utils/InfoString.cpp index 98a81bc6..9eb8c37b 100644 --- a/src/Utils/InfoString.cpp +++ b/src/Utils/InfoString.cpp @@ -74,8 +74,8 @@ namespace Utils } #endif - json11::Json InfoString::to_json() const + nlohmann::json InfoString::to_json() const { - return {this->keyValuePairs}; + return this->keyValuePairs; } } diff --git a/src/Utils/InfoString.hpp b/src/Utils/InfoString.hpp index 11f48599..3229eebb 100644 --- a/src/Utils/InfoString.hpp +++ b/src/Utils/InfoString.hpp @@ -18,7 +18,7 @@ namespace Utils void dump(); #endif - [[nodiscard]] json11::Json to_json() const; + [[nodiscard]] nlohmann::json to_json() const; private: std::unordered_map keyValuePairs; diff --git a/src/Utils/Json.cpp b/src/Utils/Json.cpp index 334ad9ef..cbf963e3 100644 --- a/src/Utils/Json.cpp +++ b/src/Utils/Json.cpp @@ -2,24 +2,33 @@ namespace Utils::Json { - std::string TypeToString(json11::Json::Type type) + std::string TypeToString(const nlohmann::json::value_t type) { switch (type) { - case json11::Json::NUL: - return "NUL"; - case json11::Json::NUMBER: - return "NUMBER"; - case json11::Json::BOOL: - return "BOOL"; - case json11::Json::STRING: - return "STRING"; - case json11::Json::ARRAY: - return "ARRAY"; - case json11::Json::OBJECT: - return "OBJECT"; + case nlohmann::json::value_t::null: + return "null"; + case nlohmann::json::value_t::number_integer: + return "number_integer"; + case nlohmann::json::value_t::number_unsigned: + return "number_unsigned"; + case nlohmann::json::value_t::number_float: + return "number_float"; + case nlohmann::json::value_t::boolean: + return "boolean"; + case nlohmann::json::value_t::string: + return "string"; + case nlohmann::json::value_t::array: + return "array"; + case nlohmann::json::value_t::object: + return "object"; + case nlohmann::json::value_t::binary: + return "binary"; + case nlohmann::json::value_t::discarded: + return "discarded"; default: - return "NUL"; + AssertUnreachable; + return "null"; } } } diff --git a/src/Utils/Json.hpp b/src/Utils/Json.hpp index 0c76fab2..854811e1 100644 --- a/src/Utils/Json.hpp +++ b/src/Utils/Json.hpp @@ -2,5 +2,5 @@ namespace Utils::Json { - std::string TypeToString(json11::Json::Type type); + std::string TypeToString(nlohmann::json::value_t type); } diff --git a/src/Utils/Library.cpp b/src/Utils/Library.cpp index 2ff31f9a..178465dc 100644 --- a/src/Utils/Library.cpp +++ b/src/Utils/Library.cpp @@ -19,20 +19,18 @@ namespace Utils return Library(handle); } - Library::Library(const std::string& name, bool _freeOnDestroy) : module_(nullptr), freeOnDestroy(_freeOnDestroy) + Library::Library(const std::string& name, bool freeOnDestroy) : module_(nullptr), freeOnDestroy_(freeOnDestroy) { this->module_ = LoadLibraryExA(name.data(), nullptr, 0); } - Library::Library(const HMODULE handle) + Library::Library(const HMODULE handle) : module_(handle), freeOnDestroy_(true) { - this->module_ = handle; - this->freeOnDestroy = true; } Library::~Library() { - if (this->freeOnDestroy) + if (this->freeOnDestroy_) { this->free(); } @@ -63,6 +61,39 @@ namespace Utils return this->module_; } + std::string Library::getName() const + { + if (!this->isValid()) + return {}; + + auto path = this->getPath(); + const auto pos = path.find_last_of("/\\"); + if (pos == std::string::npos) + return path; + + return path.substr(pos + 1); + } + + std::string Library::getPath() const + { + if (!this->isValid()) + return {}; + + char name[MAX_PATH] = {0}; + GetModuleFileNameA(this->module_, name, sizeof(name)); + + return name; + } + + std::string Library::getFolder() const + { + if (!this->isValid()) + return {}; + + const auto path = std::filesystem::path(this->getPath()); + return path.parent_path().generic_string(); + } + void Library::free() { if (this->isValid()) @@ -72,4 +103,23 @@ namespace Utils this->module_ = nullptr; } + + void Library::LaunchProcess(const std::string& process, const std::string& commandLine, const std::string& currentDir) + { + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + CreateProcessA(process.data(), const_cast(commandLine.data()), nullptr, + nullptr, false, NULL, nullptr, currentDir.data(), + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) + CloseHandle(process_info.hThread); + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) + CloseHandle(process_info.hProcess); + } } diff --git a/src/Utils/Library.hpp b/src/Utils/Library.hpp index 8c999f67..bd5eddf3 100644 --- a/src/Utils/Library.hpp +++ b/src/Utils/Library.hpp @@ -9,9 +9,9 @@ namespace Utils static Library Load(const std::filesystem::path& path); static Library GetByAddress(void* address); - Library() : module_(nullptr), freeOnDestroy(false) {}; + Library() : module_(nullptr), freeOnDestroy_(false) {} Library(const std::string& name, bool freeOnDestroy); - explicit Library(const std::string& name) : module_(GetModuleHandleA(name.data())), freeOnDestroy(true) {}; + explicit Library(const std::string& name) : module_(GetModuleHandleA(name.data())), freeOnDestroy_(true) {} explicit Library(HMODULE handle); ~Library(); @@ -23,6 +23,11 @@ namespace Utils bool isValid() const; HMODULE getModule() const; + std::string getName() const; + std::string getPath() const; + std::string getFolder() const; + std::uint8_t* getPtr() const; + void free(); template T getProc(const std::string& process) const @@ -62,10 +67,10 @@ namespace Utils return T(); } - void free(); + static void LaunchProcess(const std::string& process, const std::string& commandLine, const std::string& currentDir); private: HMODULE module_; - bool freeOnDestroy; + bool freeOnDestroy_; }; } diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 55cd12a0..360c5032 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -92,14 +92,14 @@ namespace Utils return elems; } - void Replace(std::string &string, const std::string& find, const std::string& replace) + void Replace(std::string& str, const std::string& from, const std::string& to) { - size_t nPos = 0; + std::size_t nPos = 0; - while ((nPos = string.find(find, nPos)) != std::string::npos) + while ((nPos = str.find(from, nPos)) != std::string::npos) { - string = string.replace(nPos, find.length(), replace); - nPos += replace.length(); + str = str.replace(nPos, from.length(), to); + nPos += to.length(); } } diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index b6b376ba..1f1edd2f 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -78,7 +78,7 @@ namespace Utils std::string ToUpper(std::string text); bool Compare(const std::string& lhs, const std::string& rhs); std::vector Split(const std::string& str, char delim); - void Replace(std::string& string, const std::string& find, const std::string& replace); + void Replace(std::string& str, const std::string& from, const std::string& to); bool StartsWith(const std::string& haystack, const std::string& needle); bool EndsWith(const std::string& haystack, const std::string& needle); bool IsNumber(const std::string& str); diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp index 6d9cd4df..075b0917 100644 --- a/src/Utils/Utils.cpp +++ b/src/Utils/Utils.cpp @@ -18,9 +18,9 @@ namespace Utils std::string ParseChallenge(const std::string& data) { - auto pos = data.find_first_of("\n "); + const auto pos = data.find_first_of("\n "); if (pos == std::string::npos) return data; - return data.substr(0, pos).data(); + return data.substr(0, pos); } void OutputDebugLastError() @@ -53,7 +53,7 @@ namespace Utils HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) return 0; - Utils::Memory::Allocator allocator; + Memory::Allocator allocator; allocator.reference(hSnapshot, [](void* handle) { CloseHandle(handle); }); PROCESSENTRY32 pe32; @@ -81,12 +81,12 @@ namespace Utils void* GetThreadStartAddress(HANDLE hThread) { - HMODULE ntdll = Utils::GetNTDLL(); + HMODULE ntdll = GetNTDLL(); if (!ntdll) return nullptr; static uint8_t ntQueryInformationThread[] = { 0xB1, 0x8B, 0xAE, 0x8A, 0x9A, 0x8D, 0x86, 0xB6, 0x91, 0x99, 0x90, 0x8D, 0x92, 0x9E, 0x8B, 0x96, 0x90, 0x91, 0xAB, 0x97, 0x8D, 0x9A, 0x9E, 0x9B }; // NtQueryInformationThread - NtQueryInformationThread_t NtQueryInformationThread = NtQueryInformationThread_t(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast(ntQueryInformationThread), sizeof ntQueryInformationThread), -1).data())); + NtQueryInformationThread_t NtQueryInformationThread = NtQueryInformationThread_t(GetProcAddress(ntdll, String::XOR(std::string(reinterpret_cast(ntQueryInformationThread), sizeof ntQueryInformationThread), -1).data())); if (!NtQueryInformationThread) return nullptr; HANDLE dupHandle, currentProcess = GetCurrentProcess(); @@ -106,13 +106,18 @@ namespace Utils void SetEnvironment() { - wchar_t exeName[512]; - GetModuleFileNameW(GetModuleHandle(nullptr), exeName, sizeof(exeName) / sizeof(wchar_t)); + wchar_t* buffer{}; + std::size_t size{}; + if (_wdupenv_s(&buffer, &size, L"XLABS_MW2_INSTALL") != 0 || buffer == nullptr) + { + return; + } - auto* exeBaseName = wcsrchr(exeName, L'\\'); - exeBaseName[0] = L'\0'; + const auto _0 = gsl::finally([&] { std::free(buffer); }); - SetCurrentDirectoryW(exeName); + const std::wstring dir{buffer, size}; + SetCurrentDirectoryW(dir.data()); + SetDllDirectoryW(dir.data()); } HMODULE GetNTDLL()